说在前面的话:this的作用机制和lexical scope完全没有关系。
lexical scope(词法作用域)指的是查找变量的规则。 lexical scope与函数声明在代码中的位置有关,与函数如何被调用无关。
复习一下lexical scope:举起第一颗小栗子🌰
function foo(){
let a=1;
return function (){
console.log(a);
}
}
var a=0;
let bar=foo();
bar();// 1
barrefer的函数是在foo中定义的。可以看到变量访问与lexical scope有关,与函数的call-site(被调用位置)没有关系。
this与call-site有关
与call-site有关的意识是:我们判断函数内部的this取值,要找到调用这个函数的语句,函数如何被调用决定了函数内部的this。
下面4条rule在大多数情况下决定了this的取值:
- default binding,这也是出现频率最高的情况;
- implict binding;
- explict binding;
- new(嘻嘻终于讲到我了!)
1. default binding
function foo(){
console.log(this);
}
function bar(){
'use strict'
console.log(this);
}
foo(); // window or global object
bar(); // undefined
tip: strict mode是function-scope based; 一个函数是否在strict mode下编译运行由它自身定义的时候有关;与call-site是否是strict mode没有关系。
2. implicit binding
function foo(){
console.log(this.a);
}
var obj={
a: 1,
foo: foo
}
obj.foo(); //1
这个规则应用的场景往往是某个对象obj内部引用某个函数,然后用obj.fn()的方式调用这个函数,此时函数内部的this指向obj
3. explict binding
这个规则的应用场景与Function.prototype.call()、Function.prototype.apply()、Function.prototype.bind()有关。
4. new
在js中,并没有构造函数的概念。我们以new的方式去调用一个函数,都可以返回一个新创建的对象。这一点需要与java等语言区分开来。
lexical this in arrow function
function foo(){
setTimeout(()=>{
console.log(this.a);
},1000);
}
var obj={
a: 2019,
foo: foo
}
obj.foo(); //2019
实际上,这等价于:
function foo(){
var self=this;
setTimeout(()=>{
console.log(self.a);
},1000);
}
var obj={
a: 2019,
foo: foo
}
obj.foo(); //2019
箭头函数内部的this继承自父函数的this,实际上这就很像是lexical查找机制。