我們都知道,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函數的第一個參數了,它已經徹徹底底淪為一個和遵循詞法作用域的普通變量啦!