Заповнення масивів

Нестандартний. Не використовуйте!
Синтаксис заповнення масивів є нестандартним та був прибраний, починаючи з Firefox 58. Для варіантів використання в майбутьому розгляньте Array.prototype.map, Array.prototype.filter, стрілкові функції та оператор розпакування.

Obsolete since Gecko 58 (Firefox 58 / Thunderbird 58 / SeaMonkey 2.55)
This feature is obsolete. Although it may still work in some browsers, its use is discouraged since it could be removed at any time. Try to avoid using it.

Синтаксис заповнення масивів (array comprehension) був виразом JavaScript, який дозволяв швидко збирати новий масив, базуючись на вже існуючому масиві. Однак, він був прибраний зі стандарту та з реалізації Firefox. Не використовуйте його!

Синтаксис

[for (x of iterable) x]
[for (x of iterable) if (condition) x]
[for (x of iterable) for (y of iterable) x + y]

Опис

У заповненнях масивів дозволені наступні два види компонентів:

Перебір for-of завжди є першим компонентом. Можна використовувати більше одного перебору for-of чи if-конструкцій.

Заповнення масивів були попередньо запропоновані для стандартизації у ECMAScript 2016, вони надають корисне скорочення запису для конструювання нового масиву на основі змісту іншого масиву. Заповнення часто можуть використовуватись замість викликів map() та filter(), або як засіб їх об'єднати.

Наступне заповнення бере масив чисел та створює новий масив, де кожне з цих чисел подвоюється.

var numbers = [1, 2, 3, 4];
var doubled = [for (i of numbers) i * 2];
console.log(doubled); // виводить 2,4,6,8

Це еквівалентно наступній операції map():

var doubled = numbers.map(i => i * 2);

Заповнення також можуть використовуватись для відбору елементів, які відповідають певному виразу. Ось заповнення, яке обирає лише парні числа:

var numbers = [1, 2, 3, 21, 22, 30];
var evens = [for (i of numbers) if (i % 2 === 0) i];
console.log(evens); // виводить 2,22,30

Метод filter() може використовуватись для тієї ж самої мети:

var evens = numbers.filter(i => i % 2 === 0);

Операції з map() та filter() можна об'єднати у єдине заповнення масиву. Ось таке, що відфільтровує лише парні числа, а потім створює масив, де вони подвоєні:

var numbers = [1, 2, 3, 21, 22, 30];
var doubledEvens = [for (i of numbers) if (i % 2 === 0) i * 2];
console.log(doubledEvens); // виводить 4,44,60

Квадратні дужки заповнення масиву створюють неявний блок для області видимості. Нові змінні (такі, як i у прикладі) поводяться так, ніби вони були оголошені за допомогою let. Це означає, що вони не будуть доступні за межами заповнення.

Вхідні дані для заповнення масиву не обов'язково самі мають бути масивом; ітератори та генератори також підійдуть.

Навіть рядки можна використовувати як вхідні дані; щоб виконати наведені вище функції filter та map (на подібних до масиву об'єктах):

var str = 'abcdef';
var consonantsOnlyStr = [for (c of str) if (!(/[aeiouAEIOU]/).test(c)) c].join(''); // 'bcdf'
var interpolatedZeros = [for (c of str) c + '0' ].join(''); // 'a0b0c0d0e0f0'

Знову ж таки, початкова форма не зберігається, тому нам доведеться скористатись методом join(), щоб повернутись до рядка.

Приклади

Прості заповнення масивів

[for (i of [1, 2, 3]) i * i ]; 
// [1, 4, 9]

var abc = ['А', 'Б', 'В'];
[for (letters of abc) letters.toLowerCase()];
// ["а", "б", "в"]

Заповнення масивів з оператором if

var years = [1954, 1974, 1990, 2006, 2010, 2014];
[for (year of years) if (year > 2000) year];
// [2006, 2010, 2014]
[for (year of years) if (year > 2000) if (year < 2010) year];
// [2006], те саме, що й нижче:
[for (year of years) if (year > 2000 && year < 2010) year];
// [2006] 

Заповнення масивів у порівнянні з map та filter

Легко зрозуміти синтаксис заповнення масивів, порівнявши його з методами масиву map та filter:

var numbers = [1, 2, 3];

numbers.map(function (i) { return i * i });
numbers.map(i => i * i);
[for (i of numbers) i * i];
// усі дорівнюють [1, 4, 9]

numbers.filter(function (i) { return i < 3 });
numbers.filter(i => i < 3);
[for (i of numbers) if (i < 3) i];
// усі дорівнюють [1, 2]

Заповнення масивів з двома масивами

Використання двох переборів for-of для роботи з двома масивами:

var numbers = [1, 2, 3];
var letters = ['а', 'б', 'в'];

var cross = [for (i of numbers) for (j of letters) i + j];
// ["1а", "1б", "1в", "2а", "2б", "2в", "3а", "3б", "3в"]

var grid = [for (i of numbers) [for (j of letters) i + j]];
// [
//  ["1а", "1б", "1в"],
//  ["2а", "2б", "2в"],
//  ["3а", "3б", "3в"]
// ]

[for (i of numbers) if (i > 1) for (j of letters) if(j > 'а') i + j]
// ["2б", "2в", "3б", "3в"], те саме, що й наведене нижче:

[for (i of numbers) for (j of letters) if (i > 1) if(j > 'а') i + j]
// ["2б", "2в", "3б", "3в"]

[for (i of numbers) if (i > 1) [for (j of letters) if(j > 'а') i + j]]
// [["2б", "2в"], ["3б", "3в"]], не те саме, що наведене нижче:

[for (i of numbers) [for (j of letters) if (i > 1) if(j > 'а') i + j]]
// [[], ["2б", "2в"], ["3б", "3в"]]

Специфікації

Початково синтаксис був присутній у чорнетці ECMAScript 2015, але був видалений у ревізії 27 (серпень 2014). Будь ласка, дивіться семантику специфікації у старших ревізіях ES2015.

Сумісність з веб-переглядачами

Update compatibility data on GitHub
DesktopMobileServer
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidFirefox for AndroidOpera for AndroidSafari on iOSSamsung InternetNode.js
Array comprehensions
DeprecatedNon-standard
Chrome No support NoEdge No support NoFirefox No support 30 — 58IE No support NoOpera No support NoSafari No support NoWebView Android No support NoChrome Android No support NoFirefox Android No support 30 — 58Opera Android No support NoSafari iOS No support NoSamsung Internet Android No support Nonodejs No support No

Legend

No support  
No support
Non-standard. Expect poor cross-browser support.
Non-standard. Expect poor cross-browser support.
Deprecated. Not for use in new websites.
Deprecated. Not for use in new websites.

Відмінності від заповнень у JS1.7/JS1.8

Заповнення JS1.7/JS1.8 були прибрані з Gecko, починаючи з версії 46 (bug 1220564).

Старий синтаксис заповнень (більше не використовується!):

[X for (Y in Z)]
[X for each (Y in Z)]
[X for (Y of Z)]

Відмінності:

  • Заповнення ESNext створюють область видимості для кожного блоку "for", а не для всього заповнення.
    • Старе: [()=>x for (x of [0, 1, 2])][1]() // 2
    • Нове: [for (x of [0, 1, 2]) ()=>x][1]() // 1, кожна ітерація створює свіже зв'язування для x.
  • Заповнення ESNext починаються з "for", а не з виразу присвоювання.
    • Старе: [i * 2 for (i of numbers)]
    • Нове: [for (i of numbers) i * 2]
  • Заповнення ESNext можуть мати декілька компонентів if та for.
  • Заповнення ESNext працюють тільки з переборами for...of, а не з for...in.

Дивіться пропозиції щодо змін у коді у Bug 1220564, коментар 42.

Див. також