Що означають три крапки (...) в JavaScript?

4 хв. читання

Оператор spread для масиву/об'єкта

Припустімо, що у вас є такий об'єкт:

const adrian = {
  fullName: 'Adrian Oprea',
  occupation: 'Software developer',
  age: 31,
  website: 'https://web.archive.org/web/20230321044514/https://oprea.rocks'
};

Наприклад, ви хочете створити новий об'єкт (особу) з іншим ім'ям та сайтом, але з тією ж професією та віком.

Ви можете зробити це, вказавши лише потрібні вам властивості й використати оператор spread для решти властивостей, як у прикладі:

const bill = {
  ...adrian,
  fullName: 'Bill Gates',
  website: 'https://web.archive.org/web/20230321044514/https://microsoft.com'
};

Вищевказаний код розповсюджує об'єкт adrian й бере всі його властивості, перезаписуючи потім наявні тими, що ми передаємо. Він копіює властивості об'єкта adrian поверх щойно створеного об'єкта, а потім явно перезаписує firstName та webSite. Вважайте це розповсюдження вилученням всіх індивідуальних властивостей й перенесенням їх на новий об'єкт.

У цьому випадку, оскільки ми вказали властивості fullName й website після того, як оператор spread почав працювати, рушій JavaScript достатньо розумний і знає, що ми хочемо перезаписати початкові значення тих властивостей, які надходять з вихідного об'єкта.

Схожа ситуація з масивами. За виключенням того, що замість ключів та значень, оператор розповсюджує індекси та значення. На відміну від розповсюдження об'єкта, де ви не матимете дубльованих властивостей, оскільки саме так працюють об'єкти JavaScript (у вас не може бути об'єкта з двома властивостями fullName), в масивах можна мати повторювані значення, у тому випадку, якщо ви плануєте реалізувати щось подібне до нашого прикладу об'єкта.

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

const numbers1 = [1, 2, 3, 4, 5];
const numbers2 = [ ...numbers1, 1, 2, 6,7,8]; // це буде [1, 2, 3, 4, 5, 1, 2, 6, 7, 8]

Вважайте це заміною Array.prototype.concat.

Оператор Rest

При використанні в сигнатурі функції, де мають бути її аргументи, три крапки (які або повністю замінюють собою аргументи, або розміщуються поруч з ними) також викликають оператор rest.

Використаний у такий спосіб оператор rest дозволяє розробнику створювати функції, які можуть приймати необмежену кількість аргументів, котрі також називаються функціями арності (розмірності) змінних або варіативними функціями.

Ось простий приклад такої функції. Припустімо, ви хочете створити функцію, що підраховує суму всіх своїх аргументів. Зверніть увагу на те, що це не сума двох, трьох або чотирьох чисел, а сума всіх чисел, які функція може прийняти як аргументи.

Наївна реалізація з використанням оператора rest:

function sum(...numbers) {
	return numbers.reduce((accumulator, current) => {
		return accumulator += current;
	});
};
 
sum(1,2) // 3
sum(1,2,3,4,5) // 15

Найпростішим поясненням було б те, що оператор rest бере аргументи, які приймає функція, й вивантажує їх у масив, який ви можете використати пізніше.

Ви можете стверджувати, що можна це зробити, попросивши користувача передати масив чисел. Технічно це можливо, але це поганий UX для вашого API, оскільки користувачі очікують виклик функції підсумку з простими числами, а не зі списком чисел.

Ви також можете стверджувати, що можна використати масив arguments. Це також правда, але будьте обережні, arguments є не дійсним масивом, а лише подібним до масиву об'єктом (об'єкт з властивістю length). Для першого виклику нашої функції підсумку з минулого прикладу це має такий вигляд:

{
  '0': 1,
  '1': 2,
  'length': 2
}

Щоб керувати цим об'єктом й використовувати на ньому методи масивів, таких як reduce з минулого прикладу, вам треба зробити Array.prototype.slice.call(arguments).

Ось минула функція, написана з використанням Array#slice:

function sum() {
	const args = Array.prototype.slice.call(arguments);
	return args.reduce((accumulator, current) => {
		return accumulator += current;
	});
}

sum(1,2) // 3
sum(1,2,3,4,5) // 15

Цей код працює так само, як версія з розповсюдженням, але з деякими суттєвими відмінностями. Для початку, оптимізації компілятора V8 неможливі. Передача об'єкта arguments більшості функцій призведе до витоку. arguments — об'єкт буде передаватися за посиланням, тому V8 не може визначити тип і форму елементів всередині об'єкту arguments, оскільки вони можуть бути перезаписані функціями, які вони передають.

Більш безпечні версії передбачали б створення масиву на місці, що було б менш елегантно.

Суть в тому, що вищевказаний код може заплутати тих, хто буде його читати. Тому не робіть цього. Не слід заходити далі, ніж вказано на Mozilla Developer Network.

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 5.8K
Приєднався: 8 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація