Скорее всего, вы уже видели несколько примеров использования реструктуризующего присваивания, или destructuring. Данная синтаксическая конструкция используется для извлечения данных из массивов и объектов.
Чтобы вас не смущало такое хитрое название, можно представить процесс, не как разложение объекта или массива на его составляющие, а как простое структурированное присваивание. Проще всего понять новую синтаксическю конструкцию можно, рассмотрев пример из прошлого:
// Структурированное присваивание для массивов
var arr = ['this', 'is', 'array'];
var first = arr[0],
second = arr[1],
third = arr[2];
console.log(first, second, third); // this is array
// Структурированное присваивание для объектов
var obj = {
a: 'this',
b: 'is',
c: 'object'
};
var a = obj.a,
b = obj.b,
c = obj.c;
console.log(a, b, c); // this is object
Проще говоря, раньше приходилось записывать каждую переменную по отдельности вручную. А если приходилось иметь дело с динамическими данными, то могла понадобиться и ещё одна дополнительная переменная:
var f = function() {
return ['this', 'is', 'array'];
};
var tmp = f(),
first = tmp[0],
second = tmp[1],
third = tmp[2];
console.log(first, second, third); // this is array
С релизом ES6 всё стало в разы проще:
var f = function() {
return ['this', 'is', 'array'];
};
// ES6 destructuring для массивов
var [ first, second, third ] = f();
console.log(first, second, third); // this is array
Создание нескольких переменных одновременно из объекта настолько же простое, как и из массива. Если вы хотите создать переменную с тем же именем, что и свойство объекта, то можно использовать сокращенную конструкцию:
var obj = {
a: 'this',
b: 'is',
c: 'object'
};
var { a, b, c } = obj;
console.log(a, b, c); // this is object
В другом случае, когда имя переменной отличается от свойства, используется полный вариант:
var obj = {
a: 'this',
b: 'is',
c: 'object'
};
var { a: x, b: y, c: z } = obj;
// Данные записаны в переменные x, y и z
console.log(x, y, z); // this is object
// Переменных a, b, c не существует
console.log(a, b, c); // ReferenceError
Важно понимать отличие реструктуризующего присваивания от создания объекта с помощью литерала:
// Создание объекта
var a = 10, b = 20;
var obj = { x: a, y: b };
console.log(obj.x, obj.y); // 10 20
Создавая объект с помощью литерала, вы следуете правилу: справа находится свойство, слева − значение { свойство: значение }
. Подобное присваивание свойств интуитивно понятно, так как можно представить его, как обычное присваивание значение переменной переменная = значение
.
Однако, когда вы используете реструктуризующее присваивание, названное выше правило действует в точности наоборот { значение: свойство }
.
var a = 10, b = 20;
var obj = { x: a, y: b };
var { x: A, y: B } = obj;
console.log(A, B); // 10 20
В случае var obj = { x: a, y: b }
x и y представляют свойства объекта. В случае var { x: A, y: B } = obj;
x и y тоже представляют свойства.
Если переданного вами свойства нет в объекте, то вы получите переменную, содержащую undefined
:
var obj = { a: 1 };
// у объекта нет свойства b
var { x: a, y: b } = obj;
// переменной y будет присвоено undefined
console.log(x, y); // 1 undefined
Реструктуризующее присваивание можно использовать с любым уровнем вложенности:
var o = { zero: [{ one: 1, two: 2 }, { three: 3, four: 4 } ], five: 5 };
var { zero: [{ one: first }], five: fifth } = o;
console.log(first, fifth); // 1 5
Примитивные значения не являются объектами, но обладают свойствами и методами, которые можно получить с помощью реструктуризующего присваивания:
var { length: l, trim: t } = 'this is string';
console.log(l); // 14
console.log(t); // String.prototype.trim
Выше я уже рассматривал пример применения destructuring с массивами. В целом, применение достаточно схоже с объектами, за исключением двух ключевых особенностей:
// Строки
var [a, b, c] = 'xyz';
console.log(a, b, c); // x y z
// Коллекции DOM элементов
// Первые две ссылки со страницы
var [link1, link2] = document.links;
console.log(link1.tagName); // A
console.log(link2.textContent); // текстовое содержание ссылки
Можно использовать оператор spread при присваивании
var [a, b, ...c] = [1, 2, 3, 4, 5];
console.log(a, b, c); // 1 2 [3, 4, 5]
В данном случае переменные a и b получат соответственно значения 1
и 2
, а переменная c все оставшиеся значения в виде массива [3, 4, 5]
.
При использовании реструктуризующего присваивания можно задать параметры по умолчанию, на случай, если массив или объект не содержат присваиваемого свойства:
// Без параметра по умолчанию
var [x, y, z] = [1, 2];
console.log(x, y, z); // 1 2 undefined
// С использованием параметра по умолчанию
var [x, y, z = 3] = [1, 2];
console.log(x, y, z); // 1 2 3
Также, как и в случае с функциями, в качестве параметра по умолчанию можно передать выполнение какой-либо функции:
var calc = function(num) {
return Math.pow(num, 2);
};
var { prop: x, pow: y = calc(x)} = { prop: 4 };
console.log(x, y); // 4 16
var { prop: x, pow: y = calc(x)} = { prop: 4, pow: 10 };
console.log(x, y); // 4 10