携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第15天,点击查看活动详情
请结合上一篇文章食用。
先了解一下reference是什么。
由三个部分组成:
- base value ------属性所在的对象
- referenced name ------属性的名称
- strict reference ----是否严格
其中base value 就是属性所在的对象或者就是 EnvironmentRecord,它的值只可能是 undefined, an Object, a Boolean, a String, a Number, or an environment record 其中的一种。
举个例子:
var foo = {
bar: function () {
return this;
}
};
foo.bar(); // foo
// bar对应的Reference是:
var BarReference = {
base: foo,
propertyName: 'bar',
strict: false
};
其中,规范中提供了两个获取reference组成部分的方法,获取base.value的方法Getbase() ,和判断base的值是否为对象返回布尔值的方法IsPropertyReference(),前两个方法用于判断this指向。还有一个直接获取变量值的方法GetValue。
先说第三个小方法,比较简单:
var foo = 1;
var fooReference = {
base: EnvironmentRecord,
name: 'foo',
strict: false
};
GetValue(fooReference) // 1;
如何确定this的值? (用到了前两个方法)
1.计算MemberExpression的结果值给ref
但什么是MemberExpression?
举个例子:
function foo(){
console.log(this)
}
foo() //MemberExpression是foo,也就是ref为foo
function foo(){
return function(){
console.log(this)
}
}
foo()()//MemberExpression是foo()
var foo = {
bar :function(){
return this;
}
}
foo.bar()//MemberExpression是foo.bar
简单理解MemberExpression就是()左边的部分。
2.判断ref是不是一个Reference类型(也判断base value是否为对象)
var value = 1;
var foo = {
value: 2,
bar: function () {
return this.value;
}
}
console.log( foo.bar());//2
console.log((foo.bar)());//2
console.log((foo.bar = foo.bar)());//严格模式还是非严格模式
console.log((false || foo.bar)());//严格模式还是非严格模式
console.log((foo.bar, foo.bar)());//严格模式还是非严格模式
示例一 console.log( foo.bar())首先写出它的Referrence:
var Reference = {
base:foo,
name:'bar,
strict:'false
}
(判断是否为ref类型用到IsPropertyReference(ref); 如果返回值base value是一个对象那么就是true。然后this的值为GetBase(ref)。ok讲解完,继续。)
回归正题,写完reference后判断base.value的值,是foo,是一个对象,返回true。所以this的值为base的值foo。
所以,证明得出,this指向foo。所以return 出的value值为2。
示例二:console.log((foo.bar)());
MemberExpression为foo.bar,结果与分析示例一相同。
示例三console.log((foo.bar = foo.bar)());
示例四console.log((false || foo.bar)());
示例五console.log((foo.bar, foo.bar)());
由于非reference类型,所以严格模式this为undefined,非严格模式下指向window会输出1
再来例子:
function foo() {
console.log(this)
}
foo();
判断MemberExpression(ref)为foo,然后写出Reference:
var Reference ={
base: EnvironmentRecord,
name:"foo",
strict:false
}
base.value 非对象,返回false。用第三条判断,所以ImplicitThisValue(ref)的this指向为undefined(严格模式下)
** 我的测试环境全部非严格模式哦。**
综上所述,判断this指向整体步骤为,
1 .如果 ref 是 Reference,并且 判断base.value是否为对象,即判断IsPropertyReference(ref) 是否为 true, 若是,那么 this 的值为 GetBase(ref)----- --(对应示例1,2)
2 .如果 ref 是 Reference,并且 base value 值是 Environment Record,非对象,即IsPropertyReference(ref) 是否为 false, 那么this的值为 ImplicitThisValue(ref)==undefined(严格模式下)--------(对应最后一个例子。)
3 .如果 ref 不是 Reference(例如false || foo.bar),那么 this 的值为 undefined(严格模式)/window(非严格模式) -------- (对应示例3,4,5)
以上是this指向的原理,平常去判断this指向时只需记住:
- 函数作为对象的属性调用 => 谁调用就是谁
- 直接调用函数 => 全局是谁就是谁
- call、apply、bind的函数调用场景 => 绑定谁就是谁
- 函数的构造调用 => 新创建的对象
如果有不足,希望大家指正,接受批评。
今天学到了好多。