解读 this

解读 this


这是一篇笔记,里面的内容都是根据我学习的知识复制粘贴整理出来的
关于个人解读本人用+下划线+标注,英语文档对应的中文翻译用粗体标注,有不规范之处,请大家谅解
点击此处看原文|另一篇博文| ECMAScript5.1中文版| ECMAScript5.1 English


要想屡清楚,必须知道一下几个概念:

  • Types
  • Reference

Types

Types are further subclassified into ECMAScript language types and specification types.
ECMAScript 的类型分为语言类型和规范类型。

An ECMAScript language type corresponds to values that are directly manipulated by an ECMAScript programmer using the ECMAScript language. The ECMAScript language types are Undefined, Null, Boolean, String, Number, and Object.
ECMAScript 语言类型是开发者直接使用 ECMAScript 可以操作的。其实就是我们常说的Undefined, Null, Boolean, String, Number, 和 Object

A specification type corresponds to meta-values that are used within algorithms to describe the semantics of ECMAScript language constructs and ECMAScript language types. The specification types are Reference, List, Completion, Property Descriptor, Property Identifier, Lexical Environment, and Environment Record.
而规范类型相当于 meta-values,是用来用算法描述 ECMAScript 语言结构和 ECMAScript 语言类型的。规范类型包括:Reference ++(引用)++, List, Completion, Property Descriptor, Property Identifier, Lexical Environment, 和 Environment Record

Reference

这里的 Reference 是一个 Specification Type,也就是 “只存在于规范里的抽象类型”。它们是为了更好地描述语言的底层行为逻辑才存在的,但并不存在于实际的 js 代码中

尤雨溪大大

++不存在于代码中,只存在于运行时内存中++

The Reference type is used to explain the behaviour of such operators as delete, typeof, and the assignment operators.

Reference 类型就是用来解释诸如 deletetypeof 以及赋值等操作行为的

A Reference is a resolved name binding.

Reference 是个已解决的命名绑定

A Reference consists of three components, the base value, the referenced name and the Boolean valued strict reference flag.

The base value is either undefined, an Object, a Boolean, a String, a Number, or an environment record (10.2.1).

base value of undefined indicates that the reference could not be resolved to a binding. The referenced name is a String.

Reference 由三部分组成:

  • 基值 base value
    注: 就是属性所在的对象或者就是 EnvironmentRecord ++暂时理解为global++
    类型: undefined Object,Boolean String Number environment record
    基值为undefined时表示此引用没有绑定解析
  • 引用名称referenced name
    注: 属性的名称
    类型: String
  • 严格引用 strict reference
    注: 是否在严格模式下
    类型: Boolean
var foo = 1;
/****
    foo 对应的 Reference
    ---------------------
    {
        base: EnvironmentRecord,
        name: 'foo',
        strict: false
    }
*****/
复制代码
var foo = {
    bar:function(){
        return this;
    }
};
foo.bar(); // > foo
/****
    foo.bar 对应的 Reference
    ---------------------
    {
        base: foo,
        propertyName:'bar',
        strict: false
    }
*****/
复制代码

Reference 组成部分的方法

  • GetBase

GetBase(V). Returns the base value component of the reference V.

返回 referencebase value

  • IsPropertyReference

HasPrimitiveBase(V). Returns true if the base value is a Boolean, String, or Number.
如果基值是 Boolean, String, Number ++基本类型++,那么返回true

IsPropertyReference(V). Returns true if either the base value is an object or HasPrimitiveBase(V) is true; otherwise returns false.
如果 base value 是一个Object或者其HasPrimitiveBase()true,就返回true

  • GetValue

除此之外,紧接着在 8.7.1 章规范中就讲了一个用于从 Reference类型获取对应值的方法: GetValue。

调用 GetValue,返回的将是具体的值,而不是一个Reference

简单模拟 GetValue 的使用:

var foo = 1;
/****
    foo 对应的 Reference
    ---------------------
    var fooReference={
        base: EnvironmentRecord,
        name: 'foo',
        strict: false
    };
    GetValue(fooReference)  // > 1;
*****/
复制代码

确定this的值 直接跳过

看规范 11.2.3 Function Calls, 这里讲了当函数调用的时候,如何确定 this 的取值。

  1. Let ref be the result of evaluating MemberExpression.
    计算 MemberExpression 的结果赋值给 ref
  2. If Type(ref) is Reference, then
    判断 ref 是不是一个 Reference 类型
a.If IsPropertyReference(ref) is true, then
复制代码
i.Let thisValue be GetBase(ref).
复制代码
b.Else, the base of ref is an Environment Record
复制代码
如果 ref 是 Reference,并且 IsPropertyReference(ref) 是 true, 那么 this 的值为 GetBase(ref)
如果 ref 是 Reference,并且 base value 值是 Environment Record, 那么this的值为 ImplicitThisValue(ref)
```css i.Let thisValue be the result of calling the ImplicitThisValue concrete method of GetBase(ref). ``` 7. Else, Type(_ref_) is not Reference.
``` a. Let thisValue be undefined. ``` 如果 ref 不是 Reference,那么 this 的值为 undefined

具体分析

  1. 计算 MemberExpression 的结果赋值给 ref

什么是 MemberExpression?++当前的表达式++ | 看规范 11.2 Left-Hand-Side Expressions

MemberExpression:

  • PrimaryExpression //原始表达式 可以参见 《JavaScript权威指南第四章》
  • 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 其实就是()左边的部分。

  1. 判断 ref 是不是一个 Reference 类型。

关键就在于看规范是如何处理各种 MemberExpression,返回的结果是不是一个Reference类型

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

//示例1
console.log(foo.bar());     
//示例2
console.log((foo.bar)());
//示例3
console.log((foo.bar = foo.bar)());
//示例4
console.log((false || foo.bar)());
//示例5
console.log((foo.bar, foo.bar)());
复制代码
foo.bar()

Return a value of type Reference whose base value is baseValue and whose referenced name is propertyNameString, and whose strict mode flag is strict.
返回类型为Reference的值,其基值为baseValue 并且其引用名 ++(属性名)++ 为 propertyNameString, 严格模式标记为strict.

规范 11.2.1 Property Accessors

所以返回值为Reference,接下来按照 2.1 的判断流程走

如果 ref 是 Reference,并且 IsPropertyReference(ref) 是 true, 那么 this 的值为 GetBase(ref)

前面我们已经铺垫了 IsPropertyReference 方法,如果 base value 是一个对象,结果返回 true。

base value 为 foo,是一个对象,所以 IsPropertyReference(ref) 结果为 true。

这个时候我们就可以确定 this = GetBase(ref)

GetBase 也已经铺垫了,获得 base value 值,这个例子中就是foo,所以 this 的值就是 foo ,示例1的结果就是 2!

(foo.bar)()

Return the result of evaluating Expression. This may be of type Reference.
返回执行Expression的结果,它可能是Reference类型
NOTE This algorithm does not apply GetValue to the result of evaluating Expression.
注: 这一算法并不会作用GetValue于执行Expression的结果。这样做的原则是确保delete和typeof这样的运算符可以作用于括号括起来的表达式

规范 11.1.6 The Grouping Operator

() 并没有对 MemberExpression 进行计算,所以此式等同foo.bar

(foo.bar = foo.bar)()

有赋值号=

  1. Let rval be GetValue(rref).
    11.13.1 Simple Assignment ( = ):

返回值不为Reference类型的了,this 为 undefined,非严格模式下,this 的值为 undefined 的时候,其值会被隐式转换为全局对象。

(false || foo.bar)()
  1. Let lval be GetValue(lref).
    11.11 Binary Logical Operators

同上, 哎呀,真省事

^- 3 ^-*

复制代码
(foo.bar, foo.bar)()
  1. Call GetValue(lref).
    11.14 Comma Operator ( , )

因为使用了 GetValue,所以返回的不是 Reference 类型,this 为 undefined

普通调用
function foo() {
    console.log(this)
}
foo(); 
复制代码

MemberExpression => foo

/*
    {
        base: EnvironmentRecord,
        name: 'foo',
        strict: false
    }
*/
复制代码

The result of evaluating an identifier is always a value of type Reference with its referenced name component equal to the Identifier String.
解释执行一个标识符得到的结果必定是 Reference 类型的对象,且其引用名属性的值与 Identifier 字符串相等。

11.14 Comma Operator ( , )

因为 base value 是 EnvironmentRecord,并不是一个 Object 类型,还记得前面讲过的 base value 的取值可能吗? 只可能是 undefined, an Object, a Boolean, a String, a Number, 和 an environment record 中的一种

base value 正是 Environment Record,所以会调用 ImplicitThisValue(ref)

Object Environment Records return undefined as their ImplicitThisValue unless their provideThis flag is true.
声明式环境记录项永远将 undefined 作为其 ImplicitThisValue 返回

10.2.1.2.6 ImplicitThisValue()

所以最后 this 的值就是 undefined。

graph TB
begin(计算 MemberExpression 的结果赋值给 ref) -->isR{ref类型 == Reference?}
isR -->|Y|isP{"IsPropertyReferencer(ref)"}
isR -->|N|notP>this 的值为 undefined]
isP -->|Y|getBase>"this= GetBase(ref)"]
isP-->|N|bvIs{"baseValue==EnvironmentRecord"}
bvIs-->|Y|ImplicitThisValue>"this=ImplicitThisValue(ref)"]
ImplicitThisValue-->|恒为undefined|notP
复制代码

结束语

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值