JavaScript. Остаточные параметры и оператор расширения

28.05.2021

Теги: JavaScriptWeb-разработкаПараметрТеорияФункция

Остаточные параметры (rest)

Вызывать функцию можно с любым количеством аргументов независимо от того, как она была определена. Лишние аргументы при вызове не вызовут ошибку, просто функция в работе использует не все аргументы.

function sum(a, b) {
  return a + b;
}

alert( sum(1, 2, 3, 4, 5) );

Остаточные параметры могут быть обозначены через три точки .... Буквально это значит: «собери оставшиеся параметры и положи их в массив».

function sumAll(...args) { // args — имя массива
    let sum = 0;
    for (let arg of args) {
        sum = sum + arg;
    }
    return sum;
}

alert( sumAll(1) ); // 1
alert( sumAll(1, 2) ); // 3
alert( sumAll(1, 2, 3) ); // 6

В примере ниже первые два аргумента функции станут именем и фамилией, а третий и последующие превратятся в массив others:

function showName(firstName, lastName, ...others) {
    alert( firstName + ' ' + lastName ); // Сергей Иванов

    // Оставшиеся параметры пойдут в массив
    // others = ['Россия', 'Москва']
    alert( others[0] ); // Россия
    alert( others[1] ); // Москва
    alert( others.length ); // 2
}

showName('Сергей', 'Иванов', 'Россия', 'Москва');

Переменная arguments

Все аргументы функции находятся в псевдомассиве arguments под своими порядковыми номерами.

function showName() {
    alert( arguments.length );
    alert( arguments[0] );
    alert( arguments[1] );

    // Объект arguments можно перебирать
    // for (let arg of arguments) alert(arg);
}

// Вывод: 2, Сергей, Иванов
showName('Сергей', 'Иванов');

// Вывод: 1, Андрей, undefined (второго аргумента нет)
showName('Андрей');

Раньше в javascript не было остаточных параметров, и получить все аргументы функции можно было только с помощью arguments. Этот способ всё ещё работает, его можно встретить в старом коде.

Но у него есть один недостаток. Хотя arguments похож на массив, и его тоже можно перебирать, это всё же не массив. Он не поддерживает методы массивов, поэтому нельзя вызвать, например, arguments.map(...).

К тому же, arguments всегда содержит все аргументы функции — нет возможности получить их часть. А остаточные параметры позволяют это сделать. Соответственно, для более удобной работы с аргументами лучше использовать остаточные параметры.

Оператор расширения (spread)

Например, есть встроенная функция Math.max(). Она возвращает наибольшее число из списка:

alert( Math.max(3, 5, 1) ); // 5

Допустим, у нас есть массив чисел [3, 5, 1]. Как вызвать для него Math.max()? Просто так их не вставишь — Math.max() ожидает получить список чисел, а не один массив.

let arr = [3, 5, 1];

alert( Math.max(arr) ); // NaN

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

let arr = [3, 5, 1];

alert( Math.max(...arr) ); // 5

Этим же способом можно передать несколько итерируемых объектов:

let arr1 = [1, -2, 3, 4];
let arr2 = [8, 3, -8, 1];

alert( Math.max(...arr1, ...arr2) ); // 8

Можно даже комбинировать оператор расширения с обычными значениями:

let arr1 = [1, -2, 3, 4];
let arr2 = [8, 3, -8, 1];

alert( Math.max(1, ...arr1, 2, ...arr2, 25) ); // 25

Оператор расширения можно использовать и для слияния массивов:

let arr = [3, 5, 1];
let arr2 = [8, 9, 15];

let merged = [0, ...arr, 2, ...arr2];

alert(merged); // 0,3,5,1,2,8,9,15

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

let str = 'Привет';

alert( [...str] ); // П,р,и,в,е,т

Для этой задачи можно использовать и Array.from(). Он тоже преобразует перебираемый объект (такой как строка) в массив:

let str = 'Привет';

alert( Array.from(str) ); // П,р,и,в,е,т

Но между Array.from(obj) и [...obj] есть разница:

  • Array.from() работает как с псевдомассивами, так и с итерируемыми объектами
  • Оператор расширения работает только с итерируемыми объектами

Выходит, что если нужно сделать из чего угодно массив, то Array.from() — более универсальный метод.

Spread в литералах объекта

Клонирование объекта с одновременным добавлением дополнительных свойств:

const user = {id: 100, name: 'Сергей Иванов'};
const userWithPass = {...user, password: 'qwerty'}

console.log(userWithPass);
{id: 100, name: 'Сергей Иванов', password: 'qwerty'}

Объединяем два объекта part1 и part2 в новый объект user:

const part1 = {id: 100, name: 'Сергей Иванов'}
const part2 = {id: 100, password: 'qwerty'}

const user = {...part1, ...part2}
console.log(user);
{id: 100, name: 'Сергей Иванов', password: 'qwerty'}

Свойства объекта можно удалить с помощью деструктуризации и оператора rest. Здесь мы исключаем password, собираем оставшиеся свойства в объект rest и возвращаем этот объект из стрелочной функции.

const noPassword = ({password, ...rest}) => rest
const user = {
    id: 100,
    name: 'Сергей Иванов',
    password: 'qwerty'
}

const userNoPass = noPassword(user);
console.log(userNoPass);
{id: 100, name: 'Сергей Иванов'}

Поиск: JavaScript • Web-разработка • Параметр • Теория • Функция • rest • spread

Каталог оборудования
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.