美文网首页程序员
ECMAScript 的属性访问可能没你想到那么简单

ECMAScript 的属性访问可能没你想到那么简单

作者: 零小白 | 来源:发表于2018-09-24 19:26 被阅读4次

前言

前段时间身边有一个小伙伴问了一个关于 JavaScript 基础的问题,题目如下:

const o = {
  m() { console.log(this === o) }
}

(o.m)()

当时我的理解是,根据语法分析首先执行 o.m 的取值操作,然后其结果进行调用。因为 o.m 的执行结果是一个函数,然后函数直接被调用,所以其 this 应该在严格模式下是 undefined,非严格模式下是global,结果为 false

但是实际执行结果为 true,也就是这种调用方式和 o.m() 行为表现是一致的。再简单搜寻无果之后,我转向了 ECMAScript 规范,并在其中找到了答案。

属性访问

o.m 这种操作在规范中称为 Property Accessors 其返回的结果并不是对象 om 属性所对应的值,而是返回一个 Reference 类型的值。

  1. Return a value of type Reference whose base value component is bv, whose referenced name component is propertyKey, and whose strict reference flag is strict.

Reference 类型的值对应着一个叫做 GetValue 的方法,该方法返回的结果才是对象 om 属性所对应的值,也就是上面那个函数。就像上边引用表述的那样, Reference 类型的值其实保存了本次取值操作的对象 o 和字符串 'm'。其存在的目的是保证类似于 typeof o.mdelete o.mo.m = 'ooxx' 能够按照预期执行。本质上是因为这些操作都需要依赖 o 这个对象,而不仅仅是其 m 属性对应的值。

The Reference type is used to explain the behaviour of such operators as delete, typeof, the assignment operators, the super keyword and other language features. For example, the left-hand operand of an assignment is expected to produce a reference.

括号

然后,我们再简单的看一下括号表达式(The Grouping Operator),其规范中有很重要的一点是:

Return the result of evaluating Expression. This may be of type Reference.

规范还解释了为什么 :

This algorithm does not apply GetValue to the result of evaluating Expression. The principal motivation for this is so that operators such as delete and typeof may be applied to parenthesized expressions.

如上,官方解释了为什么不对括号里面的表达式执行结果调用 getValue 方法之后再返回,其实希望保证 deletetypeof 这些操作符和括号表达式一起工作的时候能够符合我们的预期。例如,delete (o.m)delete o.m 将会表现的一致。

结论

综上,属性访问和括号表达式共同决定了 (o.m)() 的表现和 o.m() 表现是一致的。

引申

  1. 为何 (o.n = o.m)() 会打印 false ?

那是因为赋值操作的返回结果是对右侧表达式的执行结果调用 getValue 方法,如下:

  1. Let rval be ? GetValue(rref).
  2. Perform ? DestructuringAssignmentEvaluation of assignmentPattern using rval as the argument.
  3. Return rval.

同理,你也应该知道为何 (null, o.m)() 也会打印 false

  1. 为何我在控制台中输入 o.m 显示就是相应的函数而不是一个 Reference 类型的值?

那是因为此时表达式会被解释成一条独立的语句,因此有如下规范:

  1. Let exprRef be the result of evaluating Expression.
  2. Return ? GetValue(exprRef).

这里调用了 GetValue 方法。

参考

  1. https://www.ecma-international.org/ecma-262/

相关文章

  • ECMAScript 的属性访问可能没你想到那么简单

    前言 前段时间身边有一个小伙伴问了一个关于 JavaScript 基础的问题,题目如下: 当时我的理解是,根据语法...

  • JS—属性相关

    ECMAScript中有两种属性:数据属性与访问器属性。[[]]表示内部值 数据属性 [[Enumerable]]...

  • vue双向数据绑定

    Vue双向数据绑定原理 1.属性访问器 ECMAScript中的属性分为两种:数据属性和访问器属性 1 数据属性数...

  • JS高程(二)

    面向对象 的 程序设计 ECMAScript 中 有 两种 属性:数据属性和访问器属性。 数据属性 数...

  • 第六章 面向对象的程序设计

    1.ECMAScript有两种属性:数据属性和访问器属性 2.修改属性默认的特性: defineProperty(...

  • JS高程:读书摘要(三)面向对象

    对象 属性类型 ECMAScript 中有两种属性:数据属性和访问器属性。 数据属性 数据属性有4 个描述其行为的...

  • 面向对象的程序设计

    一、理解对象 1.1属性类型 ECMAScript中有两种属性:数据属性和访问器属性1.1.1数据属性数据属性包含...

  • JavaScript基础知识(二)

    1面向对象的程序设计 1.1 属性类型 ECMAScript 中有两种属性:数据属性和访问器属性。 1.1.1数据...

  • 属性类型学习

    1.属性类型(数据属性和访问器属性) 要修改属性默认的特性,必须使用 ECMAScript 5的 Object.d...

  • 理解Javascript中的数据属性和访问属性

    理解对象 ECMAScript中有两种属性:数据属性和访问器属性 数据属性 示例1: Nodejs 中 浏览器中 ...

网友评论

    本文标题:ECMAScript 的属性访问可能没你想到那么简单

    本文链接:https://www.haomeiwen.com/subject/qohhoftx.html