Почему эта строка действительна в javascript?
var a = 0[0];
После этого a
есть undefined
.
javascript
Майкл М.
источник
источник
true[0]
или""[0]
"0"
изnew Number(0)
объекта.0[0]
вернуть значение0["toString"]
Это круто , спасибо, что указали на это.Ответы:
Когда вы это сделаете
0[0]
, интерпретатор JS превратит первый объект0
вNumber
объект, а затем попытается получить доступ к[0]
свойству этого объекта, которое естьundefined
.Нет синтаксической ошибки, потому что синтаксис доступа к свойству
0[0]
разрешен грамматикой языка в этом контексте. Эта структура (используя термины грамматики Javascript) имеет видNumericLiteral[NumericLiteral]
.Соответствующая часть грамматики языка из раздела A.3 спецификации ES5 ECMAScript следующая:
Итак, можно проследить за грамматиком в этой прогрессии:
И точно так же
Expression
может в конечном итоге бытьNumericLiteral
так, следуя грамматике, мы видим, что это разрешено:Это означает, что
0[0]
это разрешенная часть грамматики и, следовательно, без SyntaxError.Затем во время выполнения вам разрешено читать свойство, которое не существует (оно будет просто считываться как
undefined
), пока источник, из которого вы читаете, либо является объектом, либо имеет неявное преобразование в объект. И числовой литерал действительно имеет неявное преобразование в объект (объект Number).Это одна из часто неизвестных функций Javascript. Типы
Number
,Boolean
иString
в JavaScript , как правило , хранится в виде примитивов (не распустившиеся объекты). Это компактное неизменяемое представление хранилища (вероятно, сделано таким образом для эффективности реализации). Но Javascript хочет, чтобы вы могли обрабатывать эти примитивы как объекты со свойствами и методами. Итак, если вы попытаетесь получить доступ к свойству или методу, которые напрямую не поддерживаются примитивом, Javascript временно преобразует примитив в соответствующий тип объекта со значением, установленным на значение примитива.Когда вы используете объектно-подобный синтаксис для примитива, такого как
0[0]
, интерпретатор распознает это как доступ к свойству примитива. Его ответ на это - взять первый0
числовой примитив и преобразовать его в полноценныйNumber
объект, который затем может получить доступ к[0]
свойству. В этом конкретном случае[0]
свойство объекта Number -undefined
вот почему это значение, которое вы получаете0[0]
.Вот статья об автоматическом преобразовании примитива в объект для работы со свойствами:
Тайная жизнь примитивов Javascript
Вот соответствующие части спецификации ECMAScript 5.1:
9.10 CheckObjectCoercible
Выбрасывает TypeError, если значение равно
undefined
илиnull
, в противном случае возвращаетtrue
.11.2.1 Средства доступа к свойствам
Оперативная часть этого вопроса - шаг № 5 выше.
8.7.1 GetValue (V)
Это описывает, как, когда значение, к которому осуществляется доступ, является ссылкой на свойство, он вызывает,
ToObject(base)
чтобы получить версию объекта любого примитива.9.9 ToObject
Здесь описывается
Boolean
,Number
иString
примитивы преобразуются в форме объекта с [[PrimitiveValue]] внутреннее свойство множества соответственно.В качестве интересного теста, если бы код был таким:
Он по-прежнему не будет генерировать SyntaxError во время синтаксического анализа, поскольку это технически допустимый синтаксис, но он вызовет ошибку TypeError во время выполнения, когда вы запустите код, потому что, когда вышеупомянутая логика доступа к свойствам применяется к значению
x
, он будет вызыватьCheckObjectCoercible(x)
или вызыватьToObject(x)
который оба будут вызывать TypeError, еслиx
естьnull
илиundefined
.источник
0[1,2]
тоже действительно, что это значит? (Я обновляю вопрос)null
илиundefined
совершенно нормальным, даже если эти свойства не существуют.0[2]
1,2
но возвращает 2.Как и большинство языков программирования, JS использует грамматику для анализа вашего кода и преобразования его в исполняемую форму. Если в грамматике нет правила, которое можно применить к определенному фрагменту кода, он выдает ошибку SyntaxError. В противном случае код считается действительным, независимо от того, имеет ли он смысл или нет.
Соответствующие части грамматики JS :
Поскольку
0[0]
соответствует этим правилам, оно считается допустимым выражением. Правильно ли это (например, не выдает ли ошибку во время выполнения) - другой вопрос, но да, это так. Вот как JS оценивает такие выражения, какsomeLiteral[someExpression]
:someExpression
(что может быть произвольно сложным)Number
, строки => иString
т. д.)get property
операцию над результатом (2) с именем свойства result (1)Так
0[0]
интерпретируется какВот пример правильного , но неправильного выражения:
Он разбирается нормально, но во время выполнения интерпретатор не работает на шаге 2 (потому что
null
не может быть преобразован в объект) и выдает ошибку времени выполнения.источник
var x = null; var a = x[0];
не генерирует синтаксическую ошибку, но выдает ошибку TypeError во время выполнения.0[0]
значение вместо неопределенногоБывают ситуации, когда вы можете правильно указать индекс в Javascript:
Хотя не сразу понятно, зачем вам это нужно, индексирование в Javascript эквивалентно использованию точечной нотации (хотя точечная нотация ограничивает вас использованием идентификаторов в качестве ключей).
источник
(0).toString
(без вызова функции). Это свойство числового типа.0
свойство получено и , поскольку она не существует,undefined
является более правильным , как объяснено в jfriend00.0[0]
которое вернет undefined. Вполне вероятно, что так и будет, но это не обязательноЯ просто хотел бы отметить, что этот действительный синтаксис никоим образом не уникален для Javascript. Большинство языков будут иметь ошибку времени выполнения или ошибку типа, но это не то же самое, что ошибка синтаксиса. Javascript предпочитает возвращать undefined во многих ситуациях, когда другой язык может вызвать исключение, в том числе при индексировании объекта, который не имеет свойства с заданным именем.
Синтаксис не знает тип выражения (даже простого выражения, такого как числовой литерал), и позволяет применять любой оператор к любому выражению. Например, попытка присвоить индекс
undefined
илиnull
вызватьTypeError
в Javascript. Это не синтаксическая ошибка - если она никогда не выполняется (находится на неправильной стороне оператора if), это не вызовет никаких проблем, тогда как синтаксическая ошибка по определению всегда обнаруживается во время компиляции (eval, Function и т. Д. , все считается компиляцией).источник
Потому что это валидный синтаксис и даже валидный код для интерпретации. Вы можете попытаться получить доступ к любому свойству любого объекта (и в этом случае 0 будет приведен к числовому объекту), и он выдаст вам значение, если оно существует, в противном случае - неопределенное. Однако попытка доступа к свойству undefined не работает, поэтому 0 [0] [0] приведет к ошибке выполнения. Однако это все равно будет классифицироваться как допустимый синтаксис. Есть разница в том, какой синтаксис является допустимым, а какой не вызывает ошибок времени выполнения / компиляции.
источник
Действителен не только синтаксис, но и результат не обязательно должен быть,
undefined
хотя в большинстве, если не во всех разумных случаях, будет. JS - один из самых чистых объектно-ориентированных языков. Большинство так называемых объектно-ориентированных языков ориентированы на классы в том смысле, что вы не можете изменить форму (она привязана к классу) однажды созданного объекта, а только состояние объекта. В JS вы можете изменять как состояние, так и форму объекта, и это вы делаете чаще, чем вы думаете. Эта способность делает код довольно непонятным, если вы используете его неправильно. Цифры неизменяемы, поэтому вы не можете изменить сам объект, ни его состояние, ни его форму, поэтому вы можете сделатькоторое является допустимым выражением присваивания, которое возвращает 1, но на самом деле ничего не присваивает. Числовое значение
0
неизменяемо. Что само по себе несколько странно. У вас может быть действительное и правильное (исполняемое) выражение присваивания, которое ничего не присваивает (*). Однако тип числа является изменяемым объектом, поэтому вы можете изменить тип, и изменения будут каскадно распространяться по цепочке прототипов.конечно, это далеко от категории разумного использования, но язык указан для этого, потому что в других сценариях расширение возможностей объектов действительно имеет большой смысл. Вот как плагины jQuery подключаются к объекту jQuery, чтобы дать пример.
(*) Он фактически присваивает значение 1 свойству объекта, однако вы не можете ссылаться на этот (временный) объект, и, таким образом, он будет собран на проходе nexx GC.
источник
В JavaScript все является объектом, поэтому, когда интерпретатор анализирует его, он обрабатывает 0 как объект и пытается вернуть 0 как свойство. То же самое происходит, когда вы пытаетесь получить доступ к 0-му элементу со значением true или "" (пустая строка).
Даже если вы установите 0 [0] = 1, он установит свойство и его значение в памяти, но пока вы получаете доступ к 0, он обрабатывается как число (не путайте здесь обработку как объекта и числа).
источник