Нет точки с запятой перед [] вызывает ошибку в Javascript?

var a = [1,2,3,4];
var b = [10,20,30,40];
console.log([a,b].length)
[a,b].some(function(x){ x.push(x.shift()) });

Я был очень удивлен сегодня, когда этот код вызвал

[a,b].some(function(x){ x.push(x.shift()) });
      ^
TypeError: Cannot call method 'some' of undefined

очевидно, что JavaScript "автоматическая вставка точки с запятой" работает не так, как ожидалось здесь. Но почему?

Я знаю, что вы можете рекомендовать использовать ; везде, чтобы избежать чего-то подобного, но вопрос не о том, что лучше использовать ; или нет. Я хотел бы знать, что именно здесь происходит?

4 ответов


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

console.log([a,b].length)[a,b].some(function(x){ etc });

здесь вы говорите движку Javascript вызвать console.log длиной [a,b], затем посмотреть на index [a,b] результата этого вызова.

console.log возвращает строку, поэтому ваш код попытается найти свойство b той строки, которая не определена, и вызов undefined.some() не удается.

интересно отметить, что str[a,b] разрешает str[b] предполагая, что str является строкой. Как указывает Камиль,a,b является допустимым выражением Javascript, и результатом этого выражения является просто b.


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

Javascript рассматривает только новые строки, чтобы отметить конец оператора, если не завершение оператора после этой новой строки вызовет ошибку синтаксического анализа. См.каковы правила автоматической точки с запятой JavaScript вставка (ASI)? и ECMAScript 5 spec для точных правил. (Благодаря Rob W и limelights)

что происходит следующее:

код интерпретируется как

console.log([a,b].length)[a,b].some(function(x){ x.push(x.shift()) });

т. е. все как один оператор.

теперь разберите утверждение:

some вызывается по значению console.log([a,b].length)[a,b]

значение console.log([a,b].length)[a,b] вычисляется возвращаемое значение console.log([a,b].length) (undefined), а затем попытка доступа к свойству с именем значения a,b. a,b принимает значение b (попробуйте в консоли). Нет свойства со значением b of undefined, поэтому результирующее значение будет undefined как хорошо.

нет метод some on undefined, отсюда и ошибки.


JavaScript не рассматривает каждый разрыв строки как точку с запятой. Он обычно обрабатывает линию разрывы как точки с запятой, только если он не может анализировать код без точек с запятой. В принципе, JavaScript рассматривает разрыв строки как точку с запятой, если следующий символ без пробела не может быть интерпретирован как продолжение текущего оператора. JavaScript-окончательное руководство: 6-е изд. раздел 2.4

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

console.log([a,b].length)[a,b].some(function(x){ x.push(x.shift()) });

и в этом причина ошибки. JavaScript пытается выполнить доступ к массиву по результатам console.log([a,b].length). В зависимости от движка JavaScript и возвращаемого значения console.log, вы можете получать различные ошибки.


Если это последний оператор функции или потока, вы можете избежать ';' но рекомендуется ставить ';' в конце каждого оператора, чтобы избежать такой ошибки.