You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
因为 base value 是 EnvironmentRecord,并不是一个 Object 类型,还记得前面讲过的 base value 的取值可能吗? 只可能是 undefined, an Object, a Boolean, a String, a Number, 和 an environment record 中的一种。
IsPropertyReference(ref) 的结果为 false,进入下个判断:
<3> 如果 ref 是 Reference,并且 base value 值是 Environment Record, 那么this的值为 ImplicitThisValue(ref)
base value 正是 Environment Record,所以会调用 ImplicitThisValue(ref)。查看规范 10.2.1.1.6,ImplicitThisValue 方法的介绍:该函数始终返回 undefined。
所以最后 this 的值就是 undefined。
例子2:
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()
在上篇中讲到,当 JavaScript 代码执行一段可执行代码(全局代码、函数代码、eval函数)时,会创建对应的执行上下文(execution context)。
对于每个执行上下文,都有三个重要属性:
今天重点讲讲This,会涉及到ECMAScript规范和运算符优先级。
ECMAScript 5.1 规范地址:
英文版:http://es5.github.io/#x15.1
中文版:http://yanhaijing.com/es5/#115
运算符优先级:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
Type
ECMAScript 的类型分为语言类型和规范类型。
ECMAScript 语言类型是开发者直接使用 ECMAScript 可以操作的。其实就是我们常说的Undefined, Null, Boolean, String, Number, 和 Object。
规范类型它们的作用是用来描述语言底层行为逻辑。规范类型包括:Reference, List, Completion, Property Descriptor, Property Identifier, Lexical Environment, 和 Environment Record。
Reference
Reference是一个规范类型(实际并不存在),也就是说是为了解释规范某些行为而存在的,比如delete、typeof、赋值语句等。规范类型设计用于解析命名绑定的,它由三部分组成:
其实就是规范中定义了一种类型叫做Reference用来引用其他变量,它有一个规定的数据结构。由于是规范类型,所以什么情况下会返回Reference规范上也会写得一清二楚。
base value
属性所在的对象或者就是 EnvironmentRecord,它的值只可能是 undefined, an Object, a Boolean, a String, a Number, or an environment record 其中的一种。
referenced name 属性的名称。
举个例子:
再举个例子:
而且规范中还提供了获取 Reference 组成部分的方法,比如 GetBase 和 IsPropertyReference。
GetValue
从 Reference 类型获取对应值的方法,简单模拟 GetValue 的使用:
GetValue 返回对象属性真正的值,但是要注意:调用 GetValue,返回的将是具体的值,而不再是一个 Reference
如何确定this的值
当函数调用的时候,如何确定 this 的取值。如下:
具体分析
让我们一步一步看:
MemberExpression
什么是 MemberExpression?看规范 11.2 Left-Hand-Side Expressions:
MemberExpression :
举个例子:
所以简单理解 MemberExpression 其实就是()左边的部分。
判断 ref 是不是一个 Reference 类型。
关键就在于看规范是如何处理各种 MemberExpression,返回的结果是不是一个Reference类型。
例子1:
<1> MemberExpression 是 foo,解析标识符,查看规范 10.3.1 Identifier Resolution,会返回一个 Reference 类型的值:
接下来进行判断:
<2> 如果 ref 是 Reference,并且 IsPropertyReference(ref) 是 true, 那么 this 的值为 GetBase(ref)
因为 base value 是 EnvironmentRecord,并不是一个 Object 类型,还记得前面讲过的 base value 的取值可能吗? 只可能是 undefined, an Object, a Boolean, a String, a Number, 和 an environment record 中的一种。
IsPropertyReference(ref) 的结果为 false,进入下个判断:
<3> 如果 ref 是 Reference,并且 base value 值是 Environment Record, 那么this的值为 ImplicitThisValue(ref)
base value 正是 Environment Record,所以会调用 ImplicitThisValue(ref)。查看规范 10.2.1.1.6,ImplicitThisValue 方法的介绍:该函数始终返回 undefined。
所以最后 this 的值就是 undefined。
例子2:
在示例 1 中,MemberExpression 计算的结果是 foo.bar,foo.bar我们都知道是一个属性访问,那么执行属性访问的时候,basevalue为.运算符左边的语句即 foo 的结果
根据之前的内容,我们知道该值为:
1、那么ref则是Reference。
2、由于base是foo,foo是一个Object,所以 IsPropertyReference(ref) 是 true。
3、this = GetBase(ref),GetBase(ref)就是foo。
所以this的值就是foo,所以结果是2
看示例2:
foo.bar 被 () 包住,查看规范 11.1.6 The Grouping Operator
直接看结果部分,实际上 () 并没有对 MemberExpression 进行计算,所以其实跟示例 1 的结果是一样的。
看示例3,有赋值操作符,查看规范 11.13.1 Simple Assignment ( = ):
1、rval = GetValue(rref),其实就是取右边的值,由于GetValue不会返回reference类型。
2、如果 ref 不是Reference,那么 this 的值为 undefined。
this 为 undefined,非严格模式下,this 的值为 undefined 的时候,其值会被隐式转换为全局对象。
看示例4,逻辑与算法,查看规范 11.11 Binary Logical Operators:
1、lval = GetValue(lref) 同上一个,因为使用了 GetValue,所以返回的不是 Reference 类型,
2、不是reference类型,this 为 undefined
看示例5,逗号操作符,查看规范11.14 Comma Operator ( , )
1、GetValue(lref) 同上,因为使用了 GetValue,所以返回的不是 Reference 类型,
2、不是reference类型,this 为 undefined
揭晓结果
所以最后一个例子的结果是:
注意:以上是在非严格模式下的结果,严格模式下因为 this 返回 undefined,所以示例 3 会报错。
多说一句
尽管我们可以简单的理解 this 为调用函数的对象,如果是这样的话,如何解释下面这个例子呢?
所以从 ECMASciript 规范讲解 this 的指向。尽管 foo() 和 (foo.bar = foo.bar)() 最后结果都指向了 undefined,但是两者从规范的角度上却有着本质的区别。
引用
根治JS的this
JavaScript深入之从ECMAScript规范解读this
The text was updated successfully, but these errors were encountered: