前端基础 | 结合规范了解this

本文主要来源于读讶羽大佬的博客文章后的自我描述:https://github.com/mqyqingfeng/Blog/issues/7

这篇文章自己反复看了大佬文章好几遍,才在自己边写记录边重复阅读的情况下才基本看明白,四个字总结:「我太菜了」

建议将上面文章结合规范一起阅读

接上一篇执行上下文

执行上下文分为两个阶段:

  1. 创建执行上下文
  2. 执行阶段

创建执行上下文又分为 3 步:

  1. 确定 this 指向
  2. LexicalEnvironment(词法环境) 组件被创建
  3. VariableEnvironment(变量环境) 组件被创建

这里只说说 this

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

我们常说的 Undefined, Null, Boolean, String, NumberObject 属于 语言类型

规范类型「只存在于规范里的抽象类型」。它们是为了更好地描述语言的底层行为逻辑才存在的,但并不存在于实际的 js 代码中。

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

其中 Reference 类型 和 this 的指向有密切联系。

Reference 有且仅有三个组成部分:

  • base value 属性所在的对象或者就是 EnvironmentRecord,值只可能是 undefined, an Object, a Boolean, a String, a Number, or an environment record中的一种
  • referenced name 属性的名称。
  • strict reference 是否是严格模式

通过两个例子来记忆一下:

var foo = 1;

// 对应的Reference是:
var fooReference = {
    base: EnvironmentRecord,
    name: 'foo',
    strict: false
};
var foo = {
    bar: function () {
        return this;
    }
};

foo.bar(); // foo

// bar对应的Reference是:
var BarReference = {
    base: foo,
    propertyName: 'bar',
    strict: false
};

Reference 提供了两个方法:

  • GetBase: 返回 referencebase value。**返回的是一个具体值,而不再是一个 Reference**。
  • IsPropertyReference: base value 是一个对象,就返回true,否则返回 false

这里再引入一个新名词:MemberExpression

查阅ES规范:http://es5.github.io/#x11.2

MemberExpression 的值为:

  • PrimaryExpression // 原始表达式
  • FunctionExpression // 函数定义表达式
  • MemberExpression [ Expression ] // 属性访问表达式
  • MemberExpression . IdentifierName // 属性访问表达式
  • new MemberExpression Arguments // 对象创建表达式

例如:

function foo() {
    console.log(this)
}

foo(); // MemberExpression 是 foo

function foo() {
    return function() {
        console.log(this)
    }
}

foo()(); // MemberExpression 是 foo()

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

foo.bar(); // MemberExpression 是 foo.bar

简单理解 MemberExpression 其实就是()左边的部分。

如何确定 this?

建议仔细理解前面的内容!

查阅 ES规范http://es5.github.io/#x11.2.3,简单总结成2步:

  1. 计算 MemberExpression 的结果赋值给 ref
  2. 判断 ref 是不是一个 Reference 类型
    • 2.1 如果 ref 是 Reference,并且 IsPropertyReference(ref) 是 true, 那么 this 的值为 GetBase(ref)(由前面可知,GetBase(ref)即为 base value)
    • 2.2 如果 ref 是 Reference,并且 base value 值是 Environment Record, 那么this的值为 ImplicitThisValue(ref)查阅 es规范:http://es5.github.io/#x10.2.1.2.6 可知,ImplicitThisValue(ref) 函数始终返回 undefined
    • 2.3 如果 ref 不是 Reference,那么 this 的值为 undefined

如何判断是不是 Reference 类型

建议在「英文版规范」中全局搜索关键词 Return a value of type Referen,然后阅读搜索结果所属部分的内容. 得出如下结论:

两种创建 Reference 的途径:

  • 标识符解析
  • 属性访问

比如,foofoo.bar 创建了一个 Reference ,而字面量(1,“foo”,[1,3]等)或函数表达式——(function(){})却不会。有一张来自网络的图作了个概括:

reference.png

例子:

var value = 1;

var foo = {
  value: 2,
  bar: function () {
    return this.value;
  }
}

//示例1
console.log(foo.bar());

根据上述的两个步骤进行判断:

foo.bar()

  1. MemberExpression 的结果为 foo.bar
  2. 确定 foo.bar 是不是 Reference 类型(前面介绍了如何判断,不清楚的往前翻一翻):
    • 2.1 foo.bar 属于属性访问,所以它是 Reference 类型

由前文得出:

var Reference = {
  base: foo,
  name: 'bar',
  strict: false
};

由前文,判断出 IsPropertyReference(ref) 值为 true,所以 this 值为 GetBase(ref),即为 base value,所以 this 值为 foo

例子:

function foo() {
    console.log(this)
}

foo(); 

分析:

var reference = {
    base: EnvironmentRecord,
    name: 'foo',
    strict: false
}

EnvironmentRecord 不属于 Object,所以 IsPropertyReference(ref)为 false ,则 this 指向 ImplicitThisValue(ref),而前面说了,

所以 this 指向 undefined

注意:

如果你在浏览器执行上述代码,你会在控制台发现输出的是 window对象??

查阅规范http://es5.github.io/#x10.4.3
Entering Function Code」,第二条显示。

if thisArg is null or undefined, set the ThisBinding to the global object.

文章归类于: 码不停蹄

文章标签: #Javascript

版权声明: 自由转载-署名-非商用

0条评论

提示:

评论会在审核通过后显示在下方

昵称必填,用于展示在评论中

邮箱必填,不会公开展示,方便及时收到回复

网址选填,方便看到的人去访问,请完整填写,例如(http://www.brandhuang.com)

快来抢个沙发吧