JavaScript. Деструктурирующее присваивание
26.05.2021
Теги: JavaScript • Web-разработка • Массив • Переменная • Теория
Деструктурирующее присваивание — это специальный синтаксис, который позволяет нам «распаковать» массивы или объекты в кучу переменных, так как иногда они более удобны. Деструктуризацию удобно использовать со сложными функциями, которые имеют много параметров, значений по умолчанию и так далее.
Деструктуризация массива
Пример деструктуризации массива:
// есть массив с именем и фамилией let user = ['Сергей', 'Иванов'] // деструктурирующее присваивание let [name, surname] = user;
Теперь можно использовать переменные name
и surname
вместо элементов массива.
let [name, surname] = 'Сергей Иванов'.split(' ');
«Деструктурирующее присваивание» не уничтожает массив. Оно вообще ничего не делает с правой частью присваивания, его задача — только скопировать нужные значения в переменные.
Ненужные элементы массива могут быть отброшены через запятую:
// второй элемент не нужен let [name, , surname] = ['Сергей', 'Петрович', 'Иванов', 'Россия'];
Второй элемент массива пропускается, а третий присваивается переменной surname
, оставшиеся элементы массива также пропускаются (так как для них нет переменных).
На самом деле можно использовать любой перебираемый объект, не только массивы:
let [a, b, c] = 'abc'; let [one, two, three] = new Set([1, 2, 3]);
Можно использовать что угодно «присваивающее» с левой стороны, например — присвоить значания свойствам объекта:
let user = {}; [user.name, user.surname] = 'Сергей Иванов'.split(' ');
Остаточные параметры «…»
Если нужно не просто получить первые значения, но и собрать все остальные, то можно добавить ещё один параметр, который получает остальные значения, используя оператор «остаточные параметры» — троеточие.
let [name, surname, ...others] = ['Сергей', 'Иванов', 'Россия', 'студент']; // переменная others является массивом alert(others[0]); // Россия alert(others[1]); // студент alert(others.length); // 2
Значения по умолчанию
Если в массиве меньше значений, чем в присваивании, то ошибки не будет. Отсутствующие значения считаются неопределёнными:
let [name, surname] = []; alert(name); // undefined alert(surname); // undefined
Если необходимо указать значения по умолчанию:
// значения по умолчанию let [name = 'Unknown', surname = 'Unknown'] = ['Сергей']; alert(name); // Сергей (из массива) alert(surname); // Unknown (по умолчанию)
Значения по умолчанию могут быть гораздо более сложными выражениями или даже функциями. Они выполняются, только если значения отсутствуют. в примере ниже функция prompt()
будет запущена только для отсутствующего значения:
// prompt запустится только для surname let [name = prompt('Ваше имя?'), surname = prompt('Ваша фамилия?')] = ['Сергей']; alert(name); // Сергей (из массива) alert(surname); // результат prompt()
Деструктуризация объекта
Деструктурирующее присваивание также работает с объектами:
let options = { title: 'Категории', width: 100, height: 200 }; let {title, width, height} = options; alert(title); // Категории alert(width); // 100 alert(height); // 200
Порядок не имеет значения. Вот так — тоже работает:
// изменён порядок в let {...} let {height, width, title} = { title: 'Категории', height: 200, width: 100 }
Шаблон с левой стороны может быть более сложным и определять соответствие между свойствами и переменными:
let options = { title: 'Категории', width: 100, height: 200 }; // { sourceProperty: targetVariable } let {width: w, height: h, title} = options; // width -> w // height -> h // title -> title alert(title); // Категории alert(w); // 100 alert(h); // 200
Двоеточие показывает «что: куда идёт». В примере выше свойство width
сохраняется в переменную w
, свойство height
сохраняется в h
, а title
присваивается одноимённой переменной.
Для потенциально отсутствующих свойств можно установить значения по умолчанию:
let options = { title: 'Категории' }; let {title, width = 100, height = 200} = options; alert(title); // Категории alert(width); // 100 alert(height); // 200
Как и в случае с массивами, значениями по умолчанию могут быть любые выражения или даже функции. Они выполнятся, если значения отсутствуют.
let options = { title: 'Категории' }; let {title = prompt('Заголовок?'), width = prompt('Ширина?'), height = prompt('Высота?')} = options; alert(title); // Категории alert(width); // результат prompt() alert(height); // результат prompt()
Можно совмещать :
и =
:
let options = { title: 'Категории' }; let {title, width: w = 100, height: h = 200} = options; alert(title); // Категории alert(w); // 100 alert(h); // 200
Если есть большой объект с множеством свойств, можно взять только то, что нужно:
let options = { title: 'Категории', width: 100, height: 200 }; // взять только title, игнорировать остальное let { title } = options;
Остаток объекта «…»
Можно использовать троеточие, как и для массивов:
let options = { title: 'Категории', height: 200, width: 100 }; let {title, ...others} = options; // сейчас title='Категории', others={height: 200, width: 100}
В примерах выше переменные были объявлены в присваивании: let {…} = {…}
. Конечно, мы могли бы использовать существующие переменные и не указывать let
, но тут есть подвох.
let title, width, height; // ошибка будет в этой строке {title, width, height} = {title: 'Категории', width: 200, height: 100};
JavaScript считает, что видит блок кода, отсюда и ошибка. Такие блоки кода могут быть использованы для группировки операторов, например:
{ let message = 'Hello'; /* ..... */ alert(message); }
Чтобы показать JavaScript, что это не блок кода, мы можем заключить выражение в скобки ({…} = {…})
:
let title, width, height; // сейчас всё работает ({title, width, height} = {title: 'Категории', width: 200, height: 100});
Умные параметры функций
Есть ситуации, когда функция имеет много параметров, большинство из которых не обязательны:
function showMenu(title = 'Untitled', width = 200, height = 100, items = []) { /* ..... */ }
В реальной жизни проблема заключается в том, как запомнить порядок всех аргументов. Другая проблема заключается в том, как вызвать функцию, когда большинство параметров передавать не надо, и значения по умолчанию вполне подходят. Разве что вот так?
// undefined там, где подходят значения по умолчанию showMenu('Категории', undefined, undefined, ['Первый элемент меню', 'Второй элемент меню']);
Но можно передать параметры как объект, и функция немедленно деструктурирует его в переменные:
let options = { title: 'Категории', items: ['Первый элемент меню', 'Второй элемент меню'] }; // мы передаём объект в функцию... showMenu(options); // ...и она извлекает свойства в переменные function showMenu({title = 'Untitled', width = 200, height = 100, items = []}) { // title, items — взято из объекта options, // width, height — значения по умолчанию }
Можно использовать более сложное деструктурирование с вложенными объектами и двоеточием:
let options = { title: 'Категории', items: ['Первый элемент меню', 'Второй элемент меню'] }; showMenu(options); function showMenu({ title = 'Untitled', width: w = 100, // width присваиваем в w height: h = 200, // height присваиваем в h items: [item1, item2] // первый элемент items присваивается в item1, второй в item2 }) { /* ..... */ }
Полный синтаксис — такой же, как для деструктурирующего присваивания:
function({ incomingProperty: varName = defaultValue ... })
Тогда для объекта с параметрами будет создана переменная varName
для свойства с именем incomingProperty
по умолчанию равная defaultValue
.
Такое деструктурирование подразумевает, что в showMenu()
будет обязательно передан аргумент. Если нам нужны все значения по умолчанию, то нам следует передать пустой объект:
showMenu({}); // все значения по умолчанию showMenu(); // так была бы ошибка
Мы можем исправить это, сделав {}
значением по умолчанию для всего объекта параметров:
function showMenu({ title = 'Untitled', width = 100, height = 200 } = {}) { alert(`${title} ${width} ${height}`); } showMenu(); // Untitled 100 200
Поиск: JavaScript • Web-разработка • Массив • Переменная • Теория • Деструктуризация • Объект