Сокращенный синтаксис создания массивов не стандартен. В будущем используйте
Array.prototype.map, Array.prototype.filter, Стрелочные функции и spread syntax.Синтаксис array comprehension - это JavaScript-выражение, которое позволяет быстро создавать новый массив из существующего. Аналогичные сокращения существуют во многих других языках программирования.
Ниже показаны различия со старым синтаксисом Array Comprehension в SpiderMonkey, основанном на черновиках для ECMAScript 4.
Синтаксис
[for (x of итерируемый_объект) x] [for (x of итерируемый_объект) if (условие) x] [for (x of итерируемый_объект) for (y of итерируемый_объект) 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); // logs 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); // logs 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); // logs 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 = [ "A", "B", "C" ]; [for (letters of abc) letters.toLowerCase()]; // [ "a", "b", "c" ]
Сокращения с условным оператором "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], the same as below: [for (year of years) if (year > 2000 && year < 2010) year]; // [ 2006]
Сокращения в сравнении с map и filter
Простой способ понять синтаксис Array Comprehension - это сравнить его с методами Array 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 ];
// all are [ 1, 4, 9 ]
numbers.filter(function (i) { return i < 3 });
numbers.filter(i => i < 3);
[for (i of numbers) if (i < 3) i];
// all are [ 1, 2 ]
Сокращения с двумя массивами
Использование двух итераторов for-of для работы с двумя массивами:
var numbers = [ 1, 2, 3 ]; var letters = [ "a", "b", "c" ]; var cross = [for (i of numbers) for (j of letters) i+j]; // [ "1a", "1b", "1c", "2a", "2b", "2c", "3a", "3b", "3c" ] var grid = [for (i of numbers) [for (j of letters) i+j]]; // [ // ["1a", "1b", "1c"], // ["2a", "2b", "2c"], // ["3a", "3b", "3c"] // ] [for (i of numbers) if (i > 1) for (j of letters) if(j > "a") i+j] // ["2b", "2c", "3b", "3c"], the same as below: [for (i of numbers) for (j of letters) if (i > 1) if(j > "a") i+j] // ["2b", "2c", "3b", "3c"] [for (i of numbers) if (i > 1) [for (j of letters) if(j > "a") i+j]] // [["2b", "2c"], ["3b", "3c"]], not the same as below: [for (i of numbers) [for (j of letters) if (i > 1) if(j > "a") i+j]] // [[], ["2b", "2c"], ["3b", "3c"]]
Спецификации
Изначально было в черновике ECMAScript 2015, но исключено в ревизии 27 (Август 2014). Смотрите старые ревизии ES2015 для уточнения семантики.
Совместимость с браузерами
| Возможность | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari |
|---|---|---|---|---|---|
| Базовая поддержка | Нет | 30 (30) | Нет | Нет | Нет |
| Возможность | Android | Chrome for Android | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile |
|---|---|---|---|---|---|---|
| Базовая поддержка | Нет | Нет | 30.0 (30) | Нет | Нет | Нет |
Специфика работы SpiderMonkey
letне поддерживается как идентификатор, так как он доступен только в JS версии 1.7 и XUL-скриптах.- Деструктуризация сокращений не поддерживается (баг 980828).
Отличия от старой версии JS1.7/JS1.8
Старый синтаксис (не используйте его больше!):
[X for (Y in Z)]
[X for each (Y in Z)]
[X for (Y of Z)]
Различия:
- Сокращения в ESNext создают одну область для элемента "for" вместо области для всех элементов for в целом.
- Old:
[()=>x for (x of [0, 1, 2])][1]() // 2 - New:
[for (x of [0, 1, 2]) ()=>x][1]() // 1, каждая итерация создаёт свежую связку с x.
- Old:
- Сокращения в ESNext начинаются с "for" вместо присваиваемой переменной.
- Old:
[i * 2 for (i of numbers)] - New:
[for (i of numbers) i * 2]
- Old:
- Сокращения в ESNext могут иметь несколько компонентов
ifиfor. - Сокращения в ESNext работают только с итерациями вида
и не работают сfor...of.for...in
Смотрите Bug 1220564, comment 42 для внесения предложений по коду.