天天看點

ES5函數中的this和ES6箭頭函數中的this

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

繼續閱讀