javascript - 为什么 0[0] 在语法上有效?

标签 javascript

为什么这行在 javascript 中有效?

var a = 0[0];

在那之后,aundefined

最佳答案

当你执行 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 中的类型 NumberBooleanString 通常在内部存储为基元(不是完整的对象)。这些是紧凑的、不可变的存储表示(可能为了实现效率而这样做)。但是,Javascript 希望您能够像对待具有属性和方法的对象一样对待这些原语。因此,如果您尝试访问原语不直接支持的属性或方法,则 Javascript 会暂时将原语强制转换为适当类型的对象,并将值设置为原语的值。

当您在诸如 0[0] 之类的基元上使用类似对象的语法时,解释器会将其识别为对基元的属性访问。它对此的响应是采用第一个 0 数字基元并将其强制转换为一个完整的 Number 对象,然后它可以访问 [0]属性。在这种特定情况下,Number 对象的 [0] 属性是 undefined,这就是您从 0[0] 获得的值的原因.

这是一篇关于为了处理属性而将基元自动转换为对象的文章:

The Secret Life of Javascript Primitives


以下是 ECMAScript 5.1 规范的相关部分:

9.10 CheckObjectCoercible

如果值为 undefinednull 则抛出 TypeError,否则返回 true

enter image description here

11.2.1 Property Accessors

  1. Let baseReference be the result of evaluating MemberExpression.
  2. Let baseValue be GetValue(baseReference).
  3. Let propertyNameReference be the result of evaluating Expression.
  4. Let propertyNameValue be GetValue(propertyNameReference).
  5. Call CheckObjectCoercible(baseValue).
  6. Let propertyNameString be ToString(propertyNameValue).
  7. If the syntactic production that is being evaluated is contained in strict mode code, let strict be true, else let strict be false.
  8. 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 步。

8.7.1 GetValue (V)

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

9.9 ToObject

这描述了如何将 BooleanNumberString 基元转换为具有相应 [[PrimitiveValue]] 内部属性设置的对象形式.


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

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

它仍然不会在解析时抛出 SyntaxError,因为这是技术上合法的语法,但是当您运行代码时它会在运行时抛出 TypeError,因为当上述 Property Accessors 逻辑应用于 x 的值时,它会调用 CheckObjectCoercible(x) 或调用 ToObject(x) 如果 x,它们都会抛出 TypeError >nullundefined

关于javascript - 为什么 0[0] 在语法上有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29250950/

相关文章:

javascript - jsp页面中没有加载jquery

模块化方法中的 Javascript 对象排序和添加新属性

javascript - 在可滚动的div angularjs中滚动到顶部

javascript - 如何包装 HTML 内容?

javascript - Sequelize,在不提交事务的情况下在插入后立即读取插入行的 id

javascript - jQuery - 如果单击 div 或打开/关闭按钮外部如何删除类

javascript - 为什么这个 'eloquent Javascript' 递归解决方案有效?

javascript - 带有动态键的 TypeScript array.map()

javascript - 我有 8 个单行数组,如何将它们组合成一个 8 行的数组?

javascript - jQuery 解除绑定(bind)后如何绑定(bind)?