Използване на оператор за разпространение няколко пъти в javascript?

Защо операторът за разпространение не може да се използва няколко пъти?

let arr = [[[1, 2, 3]]];

console.log(arr); // Array [ Array[1] ]
console.log(...arr); // Array [ Array[3] ]
console.log(...(...arr));
// SyntaxError: expected '=>' after argument list, got ')'

Бих очаквал:

console.log(...(...arr)); // Array [ 1, 2, 3 ]

person madox2    schedule 26.01.2016    source източник
comment
...(arr) работи. същото е като ...arr   -  person madox2    schedule 26.01.2016
comment
Според спецификацията на ES6, когато се срещне операторът за разпространение, се създава итератор от обект за разпространение, който е резултат от оценяване на израза за присвояване, който е във вашия работен пример arr напр. ...arr. С console.log(...(...arr)); вие се опитвате да предадете оператор за разпространение + израз за присвояване като израз за присвояване към друг оператор за разпространение. Вижте ecma-international.org/ecma-262/6.0/ #sec-argument-lists   -  person br3w5    schedule 26.01.2016
comment
Може да искате да опитате console.log(...[].concat(...arr)) (или друга функция flattening)   -  person Bergi    schedule 26.01.2016
comment


Отговори (4)


Защо операторът за разпространение не може да се използва няколко пъти?

... не е оператор. (...arr) не е валиден JavaScript. ... е позволено само в литералите на масива и в списъците с аргументи, но това са специални форми на синтаксиса (забележете ... в производствените правила по-долу).

ArrayLiteral

ArrayLiteral :
  [ Elision_opt ]
  [ ElementList ]
  [ ElementList , Elision_opt ]

ElementList :
  Elision_opt SpreadElement
  ElementList , Elision_opt SpreadElement

SpreadElement:
  ... AssignmentExpression

Аргументи

Arguments :
  ( )
  ( ArgumentList )

ArgumentList :
  AssignmentExpression
  ... AssignmentExpression
  ArgumentList , AssignmentExpression
  ArgumentList , ... AssignmentExpression
person Felix Kling    schedule 26.01.2016
comment
Бях убеден, че разпространението на вече разпространен масив няма да даде оценка, но се оказа, че съм грешал, защото е така. Това изглежда е единственият правилен отговор. +1 - person html_programmer; 26.01.2016
comment
@madox2: Да. Не знам кой е измислил термина оператор за разпространение, но със сигурност не е оператор в смисъла на JavaScript. Това е само знак. - person Felix Kling; 27.01.2016
comment
@FelixKling можеш ли да го обясниш малко повече? Прегледах отговора ви много пъти, но не го разбирам. - person madox2; 27.01.2016
comment
Може би искате да подкрепите въпроса, който зададох, за да получа разяснение на термина оператор: Какво всъщност е и какво не е оператор? - person hippietrail; 27.01.2016
comment
@madox2: Ако считаме операторите за специална форма на функции (както е на други езици), тогава можем да кажем, че можем да използваме оператор навсякъде, където можем да използваме извикване на функция. напр. вместо var foo = add(1, 2); можем да напишем var foo = 1 + 2;. Не можем обаче да заменим var foo = spread(arr); с var foo = ...arr;. Няма такова нещо като самостоятелен оператор за разпространение, това е просто разширение на синтаксиса на инициализаторите на масиви и списъците с аргументи. И това става ясно, когато се погледне граматиката на езика. - person Felix Kling; 27.01.2016
comment
@madox2: Има и незначителен детайл, който няма да намерите rest или spread, изброени в спецификацията като оператори. :-) Защото, както казва Феликс, те са много по-ограничени от операторите и правят нещо, което нещо, което е строго оператор, не може да направи (като foo(...arrray); няма начин операторът да доведе до стойност, която да бъде предадена като дискретни аргументи към foo като това). - person T.J. Crowder; 09.08.2016

Тъй като ...arr не е като функция, която връща стойност в нормални сценарии (можете да тествате това, като просто напишете ...[[1,2,3]] в конзолата, ако ... работи като нормална функция бихме очаквали връщане от [1 2 3]. Поради тази причина не можете да верижирате спредове от MDN:

Операторът за разпространение позволява изразът да бъде разширен на места, където се очакват множество аргументи (за извикване на функции) или множество елементи (за литерали на масив).

Следователно, спредовете трябва да се случват в рамките на литералите на масива, литералите на обекта (ако използвате obj spread, което е ES7) или в рамките на извиквания на функции, така че можете да направите console.log(...[].concat(...arr))

person Geoffrey Abdallah    schedule 26.01.2016

Според това въвеждането на синтаксис за разпространение е итерируем (напр. масив), но генерира изход, който не е итерируем (напр. без масив). Така че проблемът е, че във външния синтаксис на разпространение ... като вход вие поставяте неитерируемо нещо (...arr), което причинява SyntaxError. За да изравните масива, можете да използвате плосък (ако поставите Infinity вместо 2, тогава ще изравните всеки вложен масив)

arr.flat(2)

let arr = [[[1, 2, 3]]];
console.log(arr.flat(2));

let arr2 = [[1,2,[3,4,[5,[6]]]], [[7,[8]],9]];;
console.log(arr2.flat(Infinity));

person Kamil Kiełczewski    schedule 18.02.2019

Не отговарям на въпроса ви, но - като цяло, синтаксисът на трите точки ... може да се приложи към итерируем обект - масив< /em> или подобен на масив обект.

Защо операторът за разпространение не може да се използва няколко пъти?

Няма да отговоря на въпроса Защо.
Но фрагментът по-долу показва, че ...[].concat(...arr) постига това, което сте очаквали да получите, като направите ...(...arr). Вдъхновен е от този коментар.

const arr = [[[1, 2, 3]]];

console.log(JSON.stringify(arr));                  // [[[1,2,3]]]
console.log(JSON.stringify(...arr));               // [[1,2,3]]
// console.log(JSON.stringify(...(...arr)));       // SyntaxError: expect...
console.log(JSON.stringify(...[].concat(...arr))); // [1,2,3]
console.log(...[].concat(...[].concat(...arr)));   // 1 2 3
.as-console-wrapper { max-height: 100% !important; top: 0; }

person Henke    schedule 15.03.2021