Отсутствие точки с запятой перед [] вызывает ошибку в 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 7

4 ответа:

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

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

Здесь вы говорите движку Javascript вызвать console.log с длиной [a,b], а затем посмотреть на индекс [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 из undefined, поэтому результирующее значение также будет undefined.

Нет метода some на 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, Вы можете получить различные ошибки.

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