我们都知道,js中的变量是遵循词法作用域(也叫静态作用域)的,如:
let a = 'global'
function foo1() {
let a = 'local'
console.log(a)
function foo2() {
console.log(a)
}
foo2()
}
foo1()
上面函数打印出的结果为2个‘local’,因为foo2函数中没有定义变量a,因此在函数会沿着作用域向上找,直到找到foo1中的a。
我们把这里的变量a想象成this:
function foo1() {
console.log(this)
function foo2() {
console.log(this)
}
foo2()
}
foo1.call({name: 'zhangsan'})
上面函数打印出来的是{name: ‘zhangsan’}对象和window对象,因此这里的this是不遵循词法作用域的,如果没有给foo2传this,它这里不会沿着函数往上找的,而是直接就定义为window对象,所以以前如果要用foo1中的this,就必须把它传给foo2,常见的写法有三种:
法一:
function foo1() {
console.log(this)
let _this = this
function foo2() {
console.log(_this)
}
foo2()
}
foo1.call({name: 'zhangsan'})
这种写法是将this转化成一个普通变量, 这样就遵循词法作用域了, 于是两次打印的结果一样,均打印出{name:’zhangsan’},foo2中的_this就是foo1中的_this,也就是foo1中的this。
法二:
function foo1() {
console.log(this)
function foo2() {
console.log(this)
}
foo2.call(this)
}
foo1.call({name: 'zhangsan'})
这种写法是将foo1中的this通过call函数传递给foo2,这样两处的this就是一样的了,同样打印出的结果为2个{name: ‘zhangsan’}
法三:
function foo1() {
console.log(this)
function foo2() {
console.log(this)
}
foo2.bind(this).call()
}
foo1.bind({name: 'zhangsan'}).call()
上述方法和第二种其实是一样的,只是先将实参通过bind函数进行传递,然后再调用函数,输出的结果同样是2个{name: ‘zhangsan’}
以上这些都是为了让this能像具有词法作用域的普通变量一样使用,终于,ES6迎来了箭头函数,让我们不用做如此多的挣扎,便可以像使用普通变量一样使用this
function foo1() {
console.log(this)
let foo2 = () => {
console.log(this)
}
foo2.call()
}
foo1.call({name: 'zhangsan'})
这里将foo2声明为箭头函数,得到的结果就是2个{name: ‘zhangsan’}啦,很神奇有木有?
当然,箭头函数中的this也有一些奇葩的地方,如:
···
let foo3 = () => {
console.log(this)
}
foo3.call({name: ‘zhangsan’})
···
这里输出的结果是window,也就是说箭头函数中的this已经彻底颠覆了我们以前对this的看法:call函数的第一个参数,也就是在箭头函数中this已经不是call函数的第一个参数了,它已经彻彻底底沦为一个和遵循词法作用域的普通变量啦!