为什么这行在 javascript 中有效?
var a = 0[0];
在那之后,a
是undefined
。
最佳答案
当你执行 0[0]
时,JS 解释器会将第一个 0
变成一个 Number
对象,然后尝试访问[0]
未定义
对象的属性。
没有语法错误,因为在此上下文中的语言语法允许属性访问语法 0[0]
。这种结构(使用 Javascript 语法中的术语)是 NumericLiteral[NumericLiteral]
。
语言语法的相关部分来自section A.3 ES5 ECMAScript 规范是这样的:
Literal ::
NullLiteral
BooleanLiteral
NumericLiteral
StringLiteral
RegularExpressionLiteral
PrimaryExpression :
this
Identifier
Literal
ArrayLiteral
ObjectLiteral
( Expression )
MemberExpression :
PrimaryExpression
FunctionExpression
MemberExpression [ Expression ]
MemberExpression . IdentifierName
new MemberExpression Arguments
因此,可以按照以下顺序遵循语法:
MemberExpression [ Expression ]
PrimaryExpression [ Expression ]
Literal [ Expression ]
NumericLiteral [ Expression ]
而且,类似地,Expression
最终也可以是 NumericLiteral
,所以在遵循语法之后,我们看到这是允许的:
NumericLiteral [ NumericLiteral ]
这意味着 0[0]
是语法的允许部分,因此没有 SyntaxError。
然后,在运行时,您可以读取一个不存在的属性(它只会被读取为 undefined
),只要您从中读取的源是对象或具有到对象的隐式转换。而且,数字字面量确实可以隐式转换为对象(Number 对象)。
这是 Javascript 中经常不为人知的特性之一。 Javascript 中的类型 Number
、Boolean
和 String
通常在内部存储为基元(不是完整的对象)。这些是紧凑的、不可变的存储表示(可能为了实现效率而这样做)。但是,Javascript 希望您能够像对待具有属性和方法的对象一样对待这些原语。因此,如果您尝试访问原语不直接支持的属性或方法,则 Javascript 会暂时将原语强制转换为适当类型的对象,并将值设置为原语的值。
当您在诸如 0[0]
之类的基元上使用类似对象的语法时,解释器会将其识别为对基元的属性访问。它对此的响应是采用第一个 0
数字基元并将其强制转换为一个完整的 Number
对象,然后它可以访问 [0]
属性。在这种特定情况下,Number 对象的 [0]
属性是 undefined
,这就是您从 0[0]
获得的值的原因.
这是一篇关于为了处理属性而将基元自动转换为对象的文章:
The Secret Life of Javascript Primitives
以下是 ECMAScript 5.1 规范的相关部分:
如果值为 undefined
或 null
则抛出 TypeError,否则返回 true
。
- Let baseReference be the result of evaluating MemberExpression.
- Let baseValue be GetValue(baseReference).
- Let propertyNameReference be the result of evaluating Expression.
- Let propertyNameValue be GetValue(propertyNameReference).
- Call CheckObjectCoercible(baseValue).
- Let propertyNameString be ToString(propertyNameValue).
- If the syntactic production that is being evaluated is contained in strict mode code, let strict be true, else let strict be false.
- Return a value of type Reference whose base value is baseValue and whose referenced name is propertyNameString, and whose strict mode flag is strict.
这个问题的执行部分是上面的第 5 步。
这描述了当被访问的值是属性引用时,它如何调用 ToObject(base)
来获取任何基元的对象版本。
这描述了如何将 Boolean
、Number
和 String
基元转换为具有相应 [[PrimitiveValue]] 内部属性设置的对象形式.
作为一个有趣的测试,如果代码是这样的:
var x = null;
var a = x[0];
它仍然不会在解析时抛出 SyntaxError,因为这是技术上合法的语法,但是当您运行代码时它会在运行时抛出 TypeError,因为当上述 Property Accessors 逻辑应用于 x 的值时
,它会调用 CheckObjectCoercible(x)
或调用 ToObject(x)
如果 x
是 ,它们都会抛出 TypeError >null
或 undefined
。
关于javascript - 为什么 0[0] 在语法上有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29250950/