Изучение двух недавних функций, которые сделают ваш код более чистым и надежным

Операторы Rest и Spread были введены в ES6 (2015) и расширены в ES9 (2018). В этой статье я объясню, что делают эти операторы, и предоставлю несколько практических примеров использования для модернизации вашего кода.

Отдыхать

параметр rest в JavaScript - это способ передачи переменного числа аргументов функции в одном параметре.

В базовом синтаксисе перед именем параметра используются три точки, и его можно использовать следующим образом:

function f(x, ...args) {
    console.log(args instanceof Array);    // -> true
    console.log(args.length);              // -> 3
    console.log(args[0]);                  // -> 2
    console.log(args[1]);                  // -> Hello
}
f(1, 2, 'Hello', 3);

Семантика ... может быть концептуализирована как «остальные параметры». Обратите внимание, что значения по умолчанию не допускаются для параметра rest, поэтому мы не можем писать ...args = 1,2,3.

Распространять

Оператор распространения можно рассматривать как инверсию параметра rest.

Вместо того, чтобы упаковывать несколько аргументов в один параметр, оператор распространения распаковывает коллекцию в отдельные значения. Начиная с ES9, оператор распространения работает с объектами, массивами и строками и может использоваться следующим образом:

function f(...args) {
    console.log(args);        // -> [1, 2, "Hello", 3]
}
const myargs = [1, 2, 'Hello', 3];
f(...myargs);

Семантику ... в операторе распространения можно представить как «распространение нескольких переменных». Итак, в приведенном выше примере элементы массива myargs распределены по четырем входным параметрам, потребляемым функцией f().

Приложения

Оператор распространения - это особенно мощный инструмент для модернизации кода JavaScript. Вот несколько практических приложений:

Объединить массивы

const a = [1,2,3];
const b = [4,5,6];
const c = [...a, ...b];    // Spread a and b across array init
console.log(c);            // -> [1, 2, 3, 4, 5, 6]

Изменить или добавить свойства объекта

const a = { x: 1, y: 2 }
const b = { ...a, x: 3 }    // Replace x property
console.log(b);             // -> { x: 3, y: 2 }
const c = { ...b, z: 4 }    // Add z property
console.log(c);             // -> { x: 3, y: 2, z: 4 }

Преобразовать строку в массив

const s = "Hello";
const a = [...s];
console.log(a);             // -> ["H", "e", "l", "l", "o"]

Комбинированное назначение отдыха и деструктуризации

Деструктуризация присваивания - еще одна языковая функция, представленная в ES6. Например, мы можем написать

const a = [1, 2];
const [b, c] = a;     // Destructure the elements of a into b and c
console.log(b)        // -> 1
console.log(c)        // -> 2
const obj = { x: 1, y: 2, z: 3 };
const {x, y, z} = obj;     // Destructure property values of obj
console.log(x);            // -> 1

Это становится невероятно эффективным в сочетании с элементами отдыха или свойствами отдыха. В контексте деструктурирования присваивания синтаксис ... имеет ту же семантику, что и в остальных параметрах, что означает «остальную часть» элементов или «остальную часть» свойств.

Некоторые примеры:

Удаление свойства из объекта

const a = { x: 1, y: 2, z: 3 };
const {x, ...b} = a;            // Destructure a into x and b
console.log(x);                 // -> 1
console.log(b);                 // -> {y: 2, z: 3}

Установите значение по умолчанию для деструктурированной переменной

const b = { x: 1, y: 2 };
const {z: z = 0, ...c} = b;   // assign zero to z if not present
console.log(c);               // -> {x: 1, y: 2}
console.log(z);               // -> 0

Еще более продвинутые варианты использования rest и spread с деструктуризацией можно найти в этом посте.

Предостережения

Оператор распространения выполняет клонирование элементов распространяемого объекта, но это всего лишь неглубокий клон. Таким образом, любые вложенные объекты будут ссылаться на свои исходные экземпляры. Например:

let q = [1,2];
const a = [q, 3];
const [b, c] = a;
q[0] = 5;
console.log(b);  // Expected 1 (deep clone), but got 5 (shallow)

Поддерживаемые браузеры

Несмотря на то, что они были представлены несколько лет назад, некоторые из этих функций не поддерживаются по умолчанию во всех современных браузерах. Вы должны проверить caniuse.com, прежде чем использовать эту функцию в своем коде, или, в качестве альтернативы, используйте промежуточный компилятор, такой как Babel, для обеспечения совместимости.

Спасибо за чтение. Если у вас есть какие-нибудь интересные приложения для отдыха и распространения, я буду рад услышать их в комментариях.