Почему точка с запятой требуется в конце строки? - PullRequest
9 голосов
/ 02 марта 2011

Почему это работает:

a = []
a.push(['test']);
(function() {alert('poop')})()

Но это выдает ошибку «число не является функцией»:

a = []
a.push(['test'])
(function() {alert('poop')})()

Единственная разница - точка с запятой в конце строки2. Я давно пишу JavaScript.Я знаю об автоматической вставке точек с запятой, но не могу понять, что может вызвать эту ошибку.

Ответы [ 7 ]

12 голосов
/ 02 марта 2011

Посмотрите на этот пример вызовов функций.

a.push(['test'])(function() {alert('poop')})()

Выглядит знакомо? Вот как компилятор / интерпретатор просматривает ваш код.

Деталь

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

CallExpression : 
	MemberExpression Arguments 
	CallExpression Arguments 
	CallExpression [ Expression ] 
	CallExpression . IdentifierName 

По существу каждая группа (...) рассматривается как Аргументы к исходному MemberExpression a.push.

a.push (['test'])                // MemberExpression Arguments 
(function() {alert('poop')})     // Arguments  
()                               // Arguments 

или более формально

CallExpression(
    CallExpression(  
        CallExpression(
            MemberExpression( a.push ),
            Arguments( (['test']) )
        ),
        Arguments( (function() {alert('poop')}) )
    ),
    Arguments( () )
)
3 голосов
/ 02 марта 2011

Я не эксперт по Javascript (или даже новичок :), но если вы объедините вторую и третью строки, это все равно выглядит синтаксически верным:

a.push(['test'])(function() {alert('poop')})()

Это пытается обработать результат a.push(['test']) как функцию, передав функцию в нее ... и затем вызывая результат как функцию.

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

1 голос
/ 02 марта 2011

В некоторых случаях пробел не требуется в качестве разделителя токенов, а используется только для улучшения читабельности:

Символы пробела используются для улучшения читаемости исходного текста и для отделения токенов (неделимых лексических единиц) друг от друга, но в остальном они незначительны. Пробелы могут появляться между любыми двумя токенами […], но не могут появляться внутри токенов любого другого типа.

В этом случае пробел между a.push(['test']) и (function() {alert('poop')})() не относится к разделителю токенов и поэтому незначителен. Так что это эквивалентно этому:

a.push(['test'])(function() {alert('poop')})()

И поскольку a ссылается на пустой массив длиной 0, вызов a.push(['test']) добавляет один элемент к a и возвращает обновленное значение a.length, т.е. 1:

1(function() {alert('poop')})()

А остальное уже история.

1 голос
/ 02 марта 2011

a.push(['test']) вернет длину массива, число. Если после точки с запятой нет, то компилятор будет интерпретировать открывающие скобки самовоспроизводящейся функции, как если бы вы пытались выполнить это число как функцию с аргументами. Допустим, он вернул длину 7, тогда, по сути, здесь происходит то, что вы написали:

7 (function() {alert('poop')})();

Следовательно, ошибка «число не является функцией», потому что она не знает, как вызвать 7 как функцию.

1 голос
/ 02 марта 2011

Поскольку

a.push(['test'])(function() {alert('poop')})()

является допустимым выражением JavaScript.И если несколько соседних строк можно соединить вместе, чтобы сформировать правильное выражение JavaScript, ваш движок JavaScript будет склеивать их вместе.

Хотя это допустимое выражение JavaScript, a.push возвращает число, которая не является функцией, и когда вы пытаетесь вызвать что-то, что не является функцией, она возвращает ошибку, которую вы видите.

0 голосов
/ 02 марта 2011

Результатом a.push () является размер возвращаемого массива, в данном случае 1. Заключенные в скобки скобки вокруг вашей функции заставляют анализатор Javascript думать, что вы пытаетесь вызвать:

1( function() {alert('poop')} )()

Или вы пытаетесь вызвать функцию с именем 1 с анонимной функцией в качестве параметра, а затем выполнить возврат как функцию.

0 голосов
/ 02 марта 2011

a.push(['test']) возвращает число.

Затем вы пытаетесь вызвать номер как функцию с function() {alert('poop')} в качестве единственного аргумента.

Отсюда ваша ошибка, number is not a function.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...