Книга: JavaScript. Подробное руководство, 6-е издание
11.3. Присваивание с разложением
11.3. Присваивание с разложением
В версии Spidermonkey 1.7 реализована разновидность составных инструкций присваивания, известная как присваивание с разложением. (Вы могли встречать присваивание с разложением в языках программирования Python или Ruby.) При присваивании с разложением значение справа от знака «равно» является массивом или объектом («составным» значением), а слева указывается одно или более имен переменных с применением синтаксиса, имитирующего литерал массива или объекта.
Инструкция присваивания с разложением извлекает (разлагает на составляющие) одно или более значений из значения справа и сохраняет в переменных, указанных слева. Кроме того, как и обычный оператор присваивания, присваивание с разложением может использоваться для инициализации вновь объявляемых переменных в инструкциях var
и let
.
Присваивание с разложением является простым и мощным инструментом при работе с массивами, и его особенно удобно использовать при работе с функциями, возвращающими массивы значений. Однако при использовании с объектами и вложенными объектами эта операция становится сложной и запутанной. Примеры, демонстрирующие простоту и сложность, приводятся ниже.
Следующий пример демонстрирует простоту присваивания с разложением при использовании с массивами значений:
let [х,у] = [1,2];
// То же, что и let х=1, у=2
[х,у] = [x+l,y+1]; // То же. что и х = х + 1, у = у+1
[х,у] = [у,х]; // Обмен значений двух переменных
console.log([х,у]);// Выведет [3,2]
Обратите внимание, как присваивание с разложением упрощает работу с функциями, возвращающими массивы значений:
// Преобразует координаты [х,у] в полярные координаты [r,theta]
function polar(x,y) {
return [Math.sqrt(x*x+y*y), Math.atan2(y,x)];
}
// Преобразует полярные координаты в декартовы координаты
function cartesian(r,theta) {
return [r*Math.cos(theta), r*Math.sin(theta)];
}
let [r,theta] = polar(1.0. 1.0); // r=Math.sqrt(2), theta=Math.PI/4
let [x,y] = cartesian(r,theta); // x=1.0, y=1.0
При выполнении присваивания с разложением количество переменных слева не обязательно должно совпадать с количеством элементов массива справа. Лишние переменные слева получат значения undefined, а лишние значения справа будут просто игнорироваться. Список переменных слева может включать дополнительные запятые, чтобы пропустить определенные значения справа:
let [х,у] = [1]; // х = 1, у = undefined
[х,у] = [1,2,3]; // х = 1, у = 2
[,х,,у] = [1,2,3,4]; // х = 2, у = 4
В JavaScript отсутствует синтаксическая конструкция, которая позволила бы присвоить переменной все оставшиеся или неиспользованные значения (как массив). Так, во второй строке в примере выше, отсутствует возможность присвоить переменной у остаток массива [2,3].
Значением инструкции присваивания с разложением является полная структура данных справа, а не отдельные значения, извлеченные из нее. То есть из операторов присваивания можно составлять «цепочки», как показано ниже:
let first, second, all;
all = [first,second] = [1,2,3,4]; // first=1, second=2, all=[1,2,3,4]
Присваивание с разложением можно даже использовать для извлечения значений из вложенных массивов. В этом случае левая сторона инструкции присваивания должна выглядеть как литерал вложенного массива:
let [one, [twoA, twoB]] = [1, [2,2.5], 3]; // twoA=2, twoB=2.5
Присваивание с разложением можно также выполнять, когда справа находится объект. В этом случае конструкция слева должна выглядеть как литерал объекта: список пар имен свойств и имен переменных, разделенных запятыми, заключенный в фигурные скобки. Имя слева от каждого двоеточия - это имя свойства, а имя справа от каждого двоеточия - это имя переменной. Каждое свойство, указанное слева, будет отыскиваться в объекте справа от оператора присваивания, и его значение (или undefined) будет присвоено соответствующей переменной. Эта разновидность присваивания с разложением может сбивать с толку, особенно если в качестве имен свойств и переменных используются одни и те же идентификаторы. Необходимо понимать, что в примере ниже r, g и b - это имена свойств, a red, green и blue - имена переменных:
let transparent = {r:0.0, g:0.0, b:0.0, а:1.0}; // Цвет в формате RGBA
let {r:red, g:green, b:blue} = transparent; // red=0.0,green=0.0,blue=0.0
Следующий пример копирует глобальные функции из объекта Math
в переменные с целью упростить программирование большого количества тригонометрических операций:
// То же, что и let sin=Math.sin, cos=Math.cos, tan=Math.tan
let {sin:sin, cos:cos, tan:tan} = Math;
Подобно тому как присваивание с разложением может использоваться при работе с вложенными массивами, эта операция может использоваться при работе с вложенными объектами. В действительности, эти два синтаксиса можно комбинировать для описания произвольных структур данных. Например:
// Вложенная структура данных: объект содержит массив объектов
let data = {
name: "присваивание с разложением",
type: "расширение",
impl: [{engine: "spidermonkey", version: 1.7},
{engine: "rhino", version: 1.7}]
};
// Использовать присваивание с разложением для извлечения
// четырех значений из структуры данных
let ({name:feature, impl: [{engine:impl1, version:v1},{engine:impl2}]} = data) {
console.log(feature); // Выведет "присваивание с разложением"
console.log(impl1); // Выведет "spidermonkey"
console.log(v1); // Выведет 1.7
console.log(impl2); // Выведет "rhino"
}
Имейте в виду, что подобные вложенные инструкции присваивания с разложением могут превратить программный код в трудночитаемые дебри, вместо того чтобы упростить его. Однако есть одна интересная закономерность, которая поможет вам разобраться в самых сложных случаях. Представьте сначала обычное присваивание (с единственным значением). После того как присваивание будет выполнено, переменную слева от оператора присваивания можно взять и использовать как выражение, которое будет возвращать присвоенное значение. Мы говорили, что в инструкции присваивания с разложением слева указывается синтаксическая конструкция, напоминающая литерал массива или объекта. Но обратите внимание, что после выполнения присваивания с разложением программный код слева, который выглядит как литерал массива или объекта, действительно будет интерпретироваться как обычный литерал массива или объекта: все необходимые переменные будут определены, и вы сможете копировать текст слева от знака «равно» и использовать его в своей программе как массив или объект.
- Присваивание значений
- 11.5. Краткая форма записи функций
- Присваивание функции результата
- Присваивание функций. Функциональный тип данных
- Составное присваивание
- 5.12.2 Присваивание сети адресов класса В
- Переменные ссылочного типа и присваивание
- Пример 4-3. Присваивание значений переменным простое и замаскированное
- 4.2. Присваивание значений переменным
- Присваивание (Assignment)
- 2.6. Присваивание характеристик динамическим эффектам
- 5.12.1 Присваивание сети адресов класса A