从ECMA规范的角度理解this的指向

1. 概念准备

ECMAScript 的类型分为语言类型和规范类型。

语言类型: Undefined, Null, Boolean, String, Number, 和 Object。

规范类型: Reference, List, Completion, Property Descriptor, Property Identifier, Lexical Environment, 和 Environment Record。

解释一下, 规范类型,也就是 “只存在于规范里的抽象类型”。

它们是为了更好地描述语言的底层行为逻辑才存在的,但并不存在于实际的 js 代码中。


其中, 这里涉及到了 Reference, 字面理解为 某个属性的参照

Reference 的构成,由三个组成部分,分别是:

  • base value (属性所在的对象, 否则就是 EnvironmentRecord) EnvironmentRecord我的理解是, 假如这个变量/属性不属于某一对象, 那么他属于某个环境
  • referenced name (属性的名称)
  • strict reference (是否严格模式)

举个例子:

var foo = 1;

// 对应的Reference是:
foo -> Reference = {
    base: EnvironmentRecord,  //不属于某一对象(当然, 非严格模式下会被挂到全局对象window)
    name: 'foo',      // 属性名 'foo'
    strict: false
};

再举个例子:

var foo = {
    bar: function () {
        return this;
    }
};

// bar对应的Reference是:
bar -> Reference = {
    base: foo,      // 明显 bar 是 foo 的属性
    name: 'bar',	// 属性名 'bar'
    strict: false
};

看完上面的例子, 你可能会问, 怎么拿到某个属性/变量的 Reference 中属性的值呢?

ECMA规定了以下方法 (当然 , js层面没法调用):

  1. Reference base 相关:
  • GetBase -> 获取Reference base值
  • IsPropertyReference -> Reference base值是对象则返回true, 从函数名来看, 用于判断是否Reference
  1. 属性值
  • GetValue -> 获取该属性的值(GetValue返回不再是一个 Reference)

2. 再来确定this的值

现在来看看确定this的整个过程

  1. 计算 MemberExpression 的结果赋值给一个变量 ref (简单理解 MemberExpression 其实就是()左边的部分。)

  2. 判断 ref 是不是一个 Reference 类型

结果:

  • 若 ref 是 Reference,且 IsPropertyReference(ref) 是 true, 那么 this 的值为 GetBase(ref)

  • 若ref是 Reference,且 base 值是 EnvironmentRecord, 那this的值为 ImplicitThisValue(ref)undefined

  • 如果 ref 不是 Reference,那么 this 的值为 undefined


上面的话很晕

通俗的来说, 过程如下:

var foo = {
    bar: function () {
        return this;
    }
};

foo.bar(); // foo
  1. 拿到 () 左边的部分 foo.bar, 赋值给 ref
  2. 判断 ref 是否 Reference , IsPropertyReference(ref), 明显 ref -> Reference > base === foo
  3. foo是对象, 则IsPropertyReference返回true, ref是Reference类型
  4. 那么, this的指向就是GetBase(ref), 也就是 foo

猜你喜欢

转载自blog.csdn.net/zdhanunity/article/details/94633942
今日推荐