Использование операторов спреда и остальных параметров
Мутирующие массивы
Когда вы передаете массив в функцию в JavaScript, он передается как ссылка. Все, что вы делаете, чтобы изменить массив внутри функции, также изменит исходный массив. например, этот код выведет [1, 2, 3] на консоль:
var array = [1, 2, 3, 4]; const mutate = arr => { arr.pop(); return arr; } mutate(array); console.log(array); // result [1, 2, 3]
копирование переданного массива в новый массив и выполнение всей обработки в новом массиве не помогает:
var array = [1, 2, 3, 4]; const mutate = arr => { var newArr = arr; newArr.pop(); return newArr; } mutate(array); console.log(array); // result [1, 2, 3] - Still mutated!
Это происходит потому, что var newArr = arr; не создает новый массив. Все это указывает новую переменную на тот же массив.
Вы можете использовать Array.from:
var newArr = Array.from(arr);
или срез():
var newArr = arr.slice();
чтобы скопировать массив, переданный в функцию, в новый массив. Затем вы можете изменить новый массив, не изменяя исходный массив.
… Другой способ…
Сегодня утром я просматривал определение остальных параметров и операторов распространения, и мне пришло в голову, что есть другой способ передать массив как значение вместо ссылки.
Параметр rest позволяет нам представить неопределенное количество аргументов в виде массива. Когда вы определяете функцию, используя остаточный параметр, аргументы функции, независимо от их количества, будут преобразованы в массив.
оператор распространения позволяет расширять итерируемый объект, например массив, на месте. Если вы используете оператор распространения при передаче массива в вызов функции, функция получит отдельные значения массива в качестве аргументов.
Если мы объединим эти две концепции, определив нашу функцию с оставшимся параметром и вызвав функцию с оператором распространения, мы сможем выполнять операции над массивом с помощью функции, не изменяя исходный массив.
var array = [1, 2, 3, 4]; // use rest parameter in function definition // to turn passed values into array const noMutate = (…arr) => { arr.pop(); return arr; } // use spread operator in function call to // turn array elements into function arguments noMutate(…array); console.log(array); // result [1, 2, 3, 4]
Передача других аргументов
Вы можете передавать другие аргументы с параметром rest, если они идут перед параметром rest. Например, вы можете реализовать собственную версию функции фильтра, которая умножает каждый элемент массива на другое число, например:
var arr = [1, 2, 3, 4]; const noMutate = (num, …arr) => { var multiple = [] for(elem of arr) multiple.push(elem * num); return multiple; } var double = noMutate(2, …arr); console.log(double); // returns [2, 4, 6, 8] console.log(arr); // not mutated: [1, 2, 3, 4]
Вы даже можете использовать оператор распространения для передачи свойств объекта JavaScript, например:
var obj = { arr: [1, 2, 3, 4] }; const noMutate = (num, …arr) => { console.log(arr); var multiple = [] for(elem of arr) multiple.push(elem * num); return multiple; } var double = noMutate(2, …obj.arr); console.log(double); // returns [2, 4, 6, 8] console.log(arr); // not mutated: [1, 2, 3, 4]
Что касается производительности, я не уверен, как это можно сравнить с использованием Array.from() или .slice(), но это устраняет одну строку кода, и я думаю, что ваш код выглядит чище. Если кто-нибудь знает, как это влияет на производительность, пожалуйста, дайте мне знать.
Статья по теме: