Ответ 1
Это не оператор.
Во всех смыслах слова это не одно. Это было огромное заблуждение, поскольку оно было введено и, несмотря на популярное мнение, - это не одно, и есть несколько объективных моментов:
- Это не соответствует определению оператора
- Он не может использоваться как оператор
- Спецификация языка подразумевает, что это не оператор
Следует отметить, что синтаксис распространения происходит в разных "вкусах", используемых в разных контекстах и обычно упоминаемых разными именами при использовании одного и того же акцента. Синтаксис Spread в основном является зонтичным термином для применения символа ...
и см. Felix Kling отличный ответ с подробным описанием всех видов использования и имен. Дополнительное объяснение об использовании этих лиц приведено в дополнительном ответе.
Что такое оператор?
Семантически, в контексте ECMAScript, операторы просто встроены в функции, которые принимают аргументы и оценивают одно значение - записываются в префикс, инфикс или постфиксную нотацию и обычно с символическими именами, такими как +
или /
. Из Wikipedia:
Просто выражение с участием оператора оценивается каким-то образом, и результирующее значение может быть просто значением (r-значение) или может быть объектом, позволяющим присваивать (l-значение).
Например, оператор +
приводит к значению, например 2, которое представляет собой правое выражение, а оператор .
приводит к объекту, позволяющему присвоить, например, foo.bar
выражение стороны.
На поверхности, ...
пунктуатор 1 выглядит префиксом унарного оператора:
const baz = [foo, ...bar];
Но проблема с этим аргументом заключается в том, что ...bar
не оценивает сингулярное значение; он разворачивает итерационные элементы bar
, один за другим. То же самое относится к аргументам распространения:
foo(...bar);
Здесь foo
получает отдельные аргументы от итерабельного bar
. Они представляют собой отдельные значения, передаваемые в foo
, а не только одно значение. Он не соответствует определению оператора, поэтому он не один.
Почему оператор не работает?
Еще один момент, который нужно сделать, заключается в том, что операторы должны быть автономными и возвращать одно значение. Например:
const bar = [...foo];
Как уже упоминалось, это хорошо работает. Проблема возникает при попытке сделать это:
const bar = ...foo;
Если синтаксис распространения был оператором, последний работал бы отлично, потому что операторы оценивали выражение для одного значения, но спрэд не так терпит неудачу. Спрэды синтаксиса и распространения аргументов работают только в контексте массивов и вызовов функций, потому что эти структуры получают несколько значений, предоставляемых путем распространения элементов массива или аргументов. Оценка нескольких значений выходит за рамки того, что может сделать оператор.
Что говорят стандарты?
Полный список операторов приведен в пп. 12.5 - 12.15 в ECMAScript 2015 Language Specification, спецификация, в которой ...
, не говоря уже о ...
. Можно также предположить, что это не оператор. Два основных случая, упомянутых в этом ответе, в которых синтаксис распространения находится в производстве, для вызовов функций (спред аргументов) или литералы массива (синтаксис распространения) описаны ниже:
ArrayLiteral : [ Elisionopt ] [ ElementList ] [ ElementList , Elisionopt ] ElementList : Elisionopt AssignmentExpression Elisionopt SpreadElement ElementList , Elisionopt AssignmentExpression ElementList , Elisionopt SpreadElement Elision : , Elision , SpreadElement : ... AssignmentExpression
И для вызовов функций:
CallExpression : MemberExpression Arguments Arguments : ( ) ( ArgumentList ) ArgumentList : AssignmentExpression ... AssignmentExpression ArgumentList , AssignmentExpression ArgumentList , ... AssignmentExpression
В этих постановках есть вывод, который можно сделать: что оператор "распространения" не существует. Как упоминалось ранее, операторы должны быть автономными, как в const bar = ...foo
, и оценивать одно значение. Синтаксис языка предотвращает это, что означает, что синтаксис распространения никогда не должен был быть автономным. Это расширение для инициализаторов массивов и вызовов функций, расширение их грамматики.
Зачем распространять синтаксис?
Синтаксис, определяемый Wikipedia:
В информатике синтаксис языка компьютера представляет собой набор правил, который определяет комбинации символов, которые считаются правильно структурированным документом или фрагментом на этом языке.
Синтаксис - это, в основном, "форма" языка, правила, которые регулируют законность или нет в отношении того, как должен выглядеть код, и как писать код. В этом случае грамматика ECMAScript специально определяет прецитера ...
только для вызова функций и литералов массива в качестве расширения - это правило, которое определяет комбинацию символов (...foo
), которые считаются законными вместе, таким образом, это синтаксис, аналогичный тому, как функция стрелки (=>
) не является оператором, а синтаксисом 2.
Вызов ...
оператор является неправильным. Оператор - встроенная функция, которая принимает аргументы (операнды) и имеет форму префикса, инфикса или постфиксной нотации и оценивает ровно одно значение. ...
, удовлетворяя первым двум условиям, не удовлетворяет последним. ...
, вместо этого, является синтаксисом, потому что он определен конкретно и явно в грамматике языка. Таким образом, "оператор распространения" объективно более корректно называют "синтаксисом распространения".
1 Термин "пунктуатор" относится к пунктуаторам в ECMAScript 2015 и более поздним спецификациям. Эти символы включают в себя синтаксические компоненты и операторы и являются точками языка. ...
- это сам признак, но термин "синтаксис распространения" относится ко всему применению пунктуатора.
2=>
сам является пунктуатором точно так же, как ...
, но я имею в виду конкретно - это синтаксис функции стрелки, применение =>
punctuator ((…) => { … }
), так же, как синтаксис распространения относится к приложению тега ...
.