Как работает оператор группировки JavaScript?

1   2; (1   2); function(){ return 1}   "text"; // SyntaxError (function(){return 1}   "text"); 

Учитывая приведенный выше код, у меня есть следующие вопросы:

  1. Почему 1 2; работать без синтаксической ошибки, тогда как function(){ return 1} "text" вызывает SyntaxError?
  2. Как оператор группировки в (function(){return 1} "text") исправляет синтаксическую ошибку?

Когда function находится в начале оператора, она рассматривается как начало определения именованной функции, которое должно выглядеть следующим образом:

 function someName() { return 1; } 

Это утверждение, а не выражение, поэтому его нельзя использовать как часть более крупного выражения.

На самом деле, недопустимо иметь это утверждение без имени. Вы получаете синтаксическую ошибку от:

 function() { return 1} 

все само по себе.

Но когда вы ставите его после скобок, это уже не начало оператора, так что это выражение функции, которое возвращает функцию в виде значения. Затем его можно использовать как подвыражение в большем выражении.

Это делает не оператор группировки, а тот факт, что это не в начале оператора. Например, вы также можете написать:

 var foo = function() { return 1 }   "text"; 

1 2; это то, что работает в большинстве языков с C-вдохновленным синтаксисом. Один из видов разрешенных операторов в Javascript — это оператор, который просто содержит выражение. Это позволяет операторам, которые просто содержат вызов функции, например, foo(); или операторы присваивания, такие как x=5; , Да, назначения в Javascript считаются выражениями, а не утверждениями, поэтому вам разрешено стрелять себе в ноги и помещать назначение в условный оператор if (классическая ошибка = vs == ). В конце концов, компилятору будет трудно запретить бесполезные выражения-выражения, такие как 1 2; все еще разрешая foo() и x = 5; ,

Функция function(){} vs (function(){}) — это причуда Javascript. Javascript имеет различные правила в грамматике для «операторов объявления функций» и «выражений функций» . В первом примере функция анализируется как оператор, который нельзя добавить к другим вещам. Во втором скобка делает функцию анализируемой как выражение, что позволяет добавлять ее к другим вещам.

Вот почему «шаблон функции самовозбуждения» всегда добавляет пару круглых скобок вокруг анонимной функции.

 (function(){ ... }()) 

Вопрос касается оператора группировки () или оператора приоритета.

Предварительное примечание: круглые скобки, используемые в «function [name] () {}», являются частью синтаксиса функции (то же самое для вызова функции), а не оператором группировки.

Оператор группировки имеет наивысший приоритет над любым другим оператором именно потому, что его роль заключается в изменении приоритета содержащегося в нем выражения (то есть в скобках). Это означает, что выражение в скобках полностью вычисляется до того, как его значение используется в оставшейся части выражения. В дальнейшем:

 (1 2); // strictly equivalent to 1 2; // because nothing more in the expression 

или:

 var x = ("3"==3)? "ok":"ko"; // grouping operator is useless as well 

… но (как указано в Barmar’answer): синтаксис «function () {return 1;}», когда он помещается между (), управляется оператором группировки и рассматривается как выражение, которое должно быть выполнено перед тем, как используется в полном заявлении, и есть 2 последствия:

  1. разрешена анонимная функция, поскольку мы находимся в выражении функции;
  2. чтобы быть выполненным, выражение функции должно иметь аргументы, предоставленные его параметрам, и -Если вы ожидаете возвращаемое значение (примечание 2) — вторая пара скобок обязательна, должна содержать аргументы или не иметь аргумента. (function () {return 1;} ());

Примечание 2: в первоначальном вопросе упоминался пример:

 (function(){return 1}   "text"); //-{amp}gt; function(){return 1}text 

как не возвращать синтаксическую ошибку: это правильно, но возвращает код функции в виде строкового значения, а не значение 1, за которым следует строка «текст». Почему? потому что круглые скобки не были предоставлены для выполнения. Мы должны написать:

 (function(){return 1}())   "text"; //-{amp}gt; 1text 
 function(){ return 1}   "text"; // SyntaxError 

Синтаксическая ошибка связана с тем, что при разделении ECMAScript ожидается, что объявление функции должно иметь имя. Итак, вы можете написать

 function foo (){return 1} "text" // result is NaN 

Почему это приводит к NaN ? Так как приведенный выше код эквивалентен следующему.

 function foo(){ return 1; }  "text" 

"text" читается как отдельное утверждение. И в соответствии со спецификацией ECMAScript оператор перед строкой приводит ее к числовому значению. Таким образом, она интерпретируется как Number("text") , которое оценивается как NaN . Вот ссылка на спецификацию ECMAScript .

введите описание изображения здесь

Почему (function(){return 1} "text") приводит к "function(){return 1}text" ?

Оператор группировки допускает анонимную функцию, поскольку выражения функций могут быть неанонимными. Оператор группировки заставляет его содержимое оцениваться как выражение. Мы знаем, что функция является подтипом объекта. Таким образом, здесь будет применяться следующее правило плюс ( ), которое также известно как оператор конкатенации:

введите описание изображения здесь

 function_Object   primitive_String ={amp}gt; ToPrmitive(function_Object )   primitive_String ={amp}gt; (function_Object).toString()   primitive_String ={amp}gt; String_representation_of_function   primitive_String 

Здесь ToPrimitive будет вызывать Function.Prototype.toString() Он будет возвращать строковое представление функции. Затем простое расхождение строк приведет к окончательному результату.

Итак, согласно приведенному выше правилу

 (function(){return 1}   "text"); 

Таким образом, результатом этого выражения будет "function(){return1}text"