为什么 0[0] 在语法上有效?
为什么这行在javascript中有效?
var a = 0[0];
之后,是 .a
undefined
当你这样做时,JS解释器会把第一个变成一个对象,然后尝试访问该对象的属性。0[0]
0
Number
[0]
undefined
没有语法错误,因为在此上下文中,语言语法允许属性访问语法。这种结构(使用Javascript语法中的术语)是 。0[0]
NumericLiteral[NumericLiteral]
ES5 ECMAScript 规范的 A.3 节中语言语法的相关部分是这样的:
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]
然后,在运行时,只要您正在读取的源是对象或具有到对象的隐式转换,就可以读取不存在的属性(它将被读取为 )。而且,数字文本确实具有对对象(Number 对象)的隐式转换。undefined
这是Javascript中经常未知的功能之一。类型和Javascript中的类型通常作为基元存储在内部(而不是完整的对象)。这些是紧凑的、不可变的存储表示(可能是为了提高实现效率而这样做的)。但是,Javascript希望你能够用属性和方法将这些基元视为对象。因此,如果您尝试访问基元上不直接支持的属性或方法,则 Javascript 会暂时将基元强制转换为适当类型的对象,并将值设置为基元的值。Number
Boolean
String
当您在原语(如 )上使用类似对象的语法时,解释器会将其识别为对基元的属性访问。它对此的回应是采用第一个数字基元并将其强制转换为一个完整的对象,然后它可以访问该属性。在此特定情况下,Number 对象上的属性就是为什么这是您从 中获取的值的原因。0[0]
0
Number
[0]
[0]
undefined
0[0]
下面是一篇关于将基元自动转换为对象以处理属性的文章:
以下是 ECMAScript 5.1 规范的相关部分:
如果值为 或,则抛出 TypeError,否则返回 。undefined
null
true
- 让 baseReference 成为评估 MemberExpression 的结果。
- Let baseValue be GetValue(baseReference).
- 让 propertyNameReference 成为计算表达式的结果。
- Let propertyNameValue be GetValue(propertyNameReference).
- Call CheckObjectCoercible(baseValue).
- Let propertyNameString be ToString(propertyNameValue).
- 如果正在评估的语法生产包含在严格模式代码中,则让 strict 为 true,否则让 strict 为 false。
- 返回一个引用类型的值,其基值为 baseValue,其引用的名称为 propertyNameString,其严格模式标志为严格。
这个问题的一个操作部分是上面的步骤#5。
这描述了当被访问的值是属性引用时,它如何调用以获取任何基元的对象版本。ToObject(base)
这描述了 如何将 和 基元 转换为具有相应设置 [[PrimitiveValue]] 内部属性的对象形式。Boolean
Number
String
作为一个有趣的测试,如果代码是这样的:
var x = null;
var a = x[0];
它仍然不会在解析时引发 SyntaxError,因为这在技术上是合法的语法,但是当您运行代码时,它会在运行时引发 TypeError,因为当上述属性访问器逻辑应用于 的值时,它将调用或调用,如果是 或,则同时引发 TypeError。x
CheckObjectCoercible(x)
ToObject(x)
x
null
undefined
像大多数编程语言一样,JS使用语法来解析代码并将其转换为可执行形式。如果语法中没有可应用于特定代码块的规则,则会引发 SyntaxError。否则,代码被视为有效,无论它是否有意义。
JS语法的相关部分是
Literal ::
NumericLiteral
...
PrimaryExpression :
Literal
...
MemberExpression :
PrimaryExpression
MemberExpression [ Expression ]
...
由于符合这些规则,因此它被视为有效的表达式。它是否正确(例如,在运行时不抛出错误)是另一回事,但确实如此。这就是 JS 计算表达式的方式,例如:0[0]
someLiteral[someExpression]
someExpression
Number
String
get property
因此被解释为0[0]
index = 0
temp = Number(0)
result = getproperty(temp, index) // it's undefined, but JS doesn't care
delete temp
return result
下面是一个有效但不正确的表达式的示例:
null[0]
它被很好地解析,但在运行时,解释器在步骤2上失败(因为无法转换为对象)并引发运行时错误。null