为什么0[0]在语法上是有效的?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (18)

为什么这一行在javascript中有效?

var a = 0[0];

在那之后,aundefined

提问于
用户回答回答于

当你做的时候0[0],JS解释器将转到第一个0变成Number对象,然后尝试访问[0]对象的undefined

没有语法错误,因为属性访问语法0[0]在此上下文中,语言语法允许。这个结构(使用Javascript语法中的术语)是NumericLiteral[NumericLiteral]

语言语法的相关部分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]是语法允许的一部分,因此没有语法错误。

然后,在运行时,可以读取不存在的属性(它将被读取为undefined)只要您从其中读取的源是一个对象,或者有一个隐式转换到一个对象。而且,数字文字实际上有一个隐式转换到一个对象(一个数字对象)。

这是Javascript中常见的未知特性之一。类型NumberBooleanString在Javascript中,通常以原语(而不是完整的对象)存储在内部。这是一种紧凑的、不可变的存储表示(可能是为了实现效率而这样做的)。但是,Javascript希望您能够像对待具有属性和方法的对象一样对待这些原语。因此,如果试图访问原语上不直接支持的属性或方法,那么Javascript将临时将原语强制为适当类型的对象,并将其值设置为原语的值。

在原语上使用类似对象的语法时,如0[0],解释器将此识别为对原语的属性访问。它对此的反应是采取第一种0数字原语,强迫它成为一个完整的Number对象,然后可以访问[0]财产开启。在这种特殊情况下,[0]属性是undefined这就是为什么你从0[0]

如果值为undefinednull,否则返回true

11.2.1属性访问器

让base Reference是评估MemberExpression的结果。

让base Value成为GetValue(Base Reference)。

让PropertyNameReference是计算表达式的结果。

设PropertyNameValue是GetValue(PropertyNameReference)。

调用CheckObjectCoer式(Base Value)。

设PropertyNameString为ToString(PropertyNameValue)。

如果正在计算的语法生成包含在严格模式代码中,则让严格为真,否则严格为假。

返回一个类型引用的值,其基值为base Value,其引用的名称为PropertyNameString,其严格模式标志是严格的。

8.7.1 GetValue(V)

这描述了当被访问的值是属性引用时,它如何调用ToObject(base)获取任何原语的对象版本。

9.9 ToObject

这描述了Boolean,Number和String元素转换为对象窗体,其中[原始价值]相应地设置内部属性。

作为一个有趣的测试,如果代码是这样的:

var x = null;
var a = x[0];

它仍然不会在解析时抛出SyntaxError,因为这在技术上是合法的语法,但是在运行时,它会在运行时抛出TypeError,因为当上面的属性访问器逻辑应用于x,它会召唤CheckObjectCoercible(x)或呼叫ToObject(x),这两种方法都会抛出一个TypeError,如果xnullundefined

用户回答回答于

与大多数编程语言一样,JS使用语法来解析代码并将其转换为可执行形式。如果语法中没有可应用于特定代码块的规则,则会抛出一个SyntaxError。否则,无论是否合理,代码都被认为是有效的。

Literal :: 
   NumericLiteral
   ...

PrimaryExpression :
   Literal
   ...

MemberExpression :
   PrimaryExpression
   MemberExpression [ Expression ]
   ...

0[0]符合这些规则,被认为是有效表情。不管是对,是这样(例如,在运行时不会抛出错误)是另一回事,但事实却是这样。这是JS计算表达式的方式,如someLiteral[someExpression]:

  1. 评估someExpression(可以是任意复杂的)
  2. 将文字转换为相应的对象类型(数字文字=>)Number,字符串=>String(等)
  3. 呼叫get property使用属性名称结果(1)对结果(2)进行操作
  4. 丢弃结果(2)

所以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无法转换为对象)并引发运行时错误。

扫码关注云+社区