在看到JavaScript深入之从ECMAScript规范解读this这篇文章之前,对this的理解仅仅是调用函数的对象。看完这篇文章之后对this的理解有了进一步的认识。
ES规范
在ES标准中,ES的类型分为语言类型和规范类型;其中语言类型就是我们在代码中可操作的类型,例如Undefined、Number、String、Boolean、Object等,规范类型是用算法来描述ES的语言结构和语言类型,包括Referenc, eList, Completion, Property Descriptor, Property Identifier, Lexical Environment, 和 Environment Record;看到这些单词时内心第一反应是:“这些是个啥?”,好在JavaScript深入之从ECMAScript规范解读this里说没懂也没有关系,只需知道ES规范中还存在一种只存在于规范里的类型,它的作用是用来描述语言底层行为逻辑。
Reference
在规范类型中我们发现了有一种叫Reference的类型,那什么是Reference呢?Reference是用来解释诸如delete、typeof和赋值等操作行为。Reference有如下三部分组成:
- base value // 属性所在的对象或者就是EnvironmentRecord,它的值只可能是undefined、string、number、boolean、object或者environmentRecord
- name // 属性的名字
- strict // 是否采用了严格模式
例如如下代码:
var foo = 1;
// 对应的Reference
var fooReference = {
baseValue: EnvironmentRecord,
name: 'foo',
strict: false
}
var foo = {
bar: function () {
return this
}
}
// foo.bar()中bar对应的Reference
var barReference = {
baseValue: foo,
name: 'bar',
strict: false
}
在ES规范中还提供了获取对应属性值的方法:
- GetBase(reference):获取Reference类型的base属性值
- IsPropertyReference(reference):判断base属性值是否为object,是的话返回true否则返回false
- GetValue(reference):获取对应变量的值,其返回值类型一定不是Reference
this的确定
说了这么多,终于进入主题了?在此之前为什么介绍Reference,主要是由于Reference和this的确定有着很大的关联;下面就来介绍ES规范中是怎么确定this的:
1. 计算MemberExpression值,赋给ref
2. 判断ref是否是Reference类型,如果是的话走第3步,不是的话就走第4步
3. 判断IsPropertyReference返回值是否为true,即baseValue是否为Object;如果是的话this就是baseValue,否则this就为undefined在非严格模式下会被转成window
4. 不是Reference的话,this的值就为undefined,在非严格模式下会被转成window
上面的第一步我们提到了“计算MemberExpression值,赋给ref”,那“计算MemberExpression值”到底是什么呢?在确定函数this的时候我们只需记住下面的话就行:
最后一个()前面的内容
例子:
function foo(){}
foo() // 对应的MemberExpression为foo
var obj = {
bar: function(){}
}
obj.bar() // 对应的MemberExpression为obj.bar
到此this的确定就基本介绍完了,下面我们看几个例子:
var val = 'outer';
var obj = {
val: 'inner',
bar: function () {
return this.value;
}
}
//示例1
console.log(obj.bar());
//示例2
console.log((obj.bar = obj.bar)());
//示例3
console.log((false || obj.bar)());
//示例4
console.log((obj.bar, obj.bar)());
示例1. obj.bar()
1.确定MemberExpression:obj.bar
2.判断是否为Reference类型:是,对应的属性值如下:
reference = {
base: obj,
name: 'bar',
strict: false
}
- 是Reference类型的情况下,判断IsPropertyReference的返回值,由于obj是对象所以返回true,那么this就是等于base属性值为obj
示例2、示例3和示例4
由于MemberExpression的值都是运算表达式,会通过GetValue来获取运算结果,上面提到过GetValue返回的值都不是Reference类型,所以ref不是Reference类型,这样的话this就是undefined,非严格模式下会被转换成window