JavaScript. Деструктурирующее присваивание

26.05.2021

Теги: JavaScriptWeb-разработкаМассивПеременнаяТеория

Деструктурирующее присваивание — это специальный синтаксис, который позволяет нам «распаковать» массивы или объекты в кучу переменных, так как иногда они более удобны. Деструктуризацию удобно использовать со сложными функциями, которые имеют много параметров, значений по умолчанию и так далее.

Деструктуризация массива

Пример деструктуризации массива:

// есть массив с именем и фамилией
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-разработка • Массив • Переменная • Теория • Деструктуризация • Объект

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.