JS中箭頭函數與this的寫法和理解
前言
JavaScript在ES6語法中新增瞭箭頭函數,相較於傳統函數,箭頭函數不僅更加簡潔,而且在this方面進行瞭改進。this作為JavaScript中比較詭異的存在,許多文章對於this的解釋也不盡相同,本篇文章試圖厘清JS中函數與this的關系。
一、JS中函數的寫法
1.常規函數的寫法
在ES6語法之前,JS中的函數由function關鍵字、params參數和被花括號包裹的函數體組成。為瞭與後面說到的箭頭函數相區別,我們先把這樣的函數叫做常規函數,常規函數既可以用聲明式寫法也可以用賦值式寫法。例子:
function test(name) { //聲明式寫法 console.log(name) } test('Jerry') let test2 = function(name) { //賦值式寫法 console.log(name) } test2('Tom')
2. 箭頭函數的寫法
ES6箭頭函數的引入,使函數的寫法變的更加簡潔,但在書寫上要遵循一定的規則。
規則一:箭頭函數隻能用賦值式寫法,不能用聲明式寫法
例子:
const test = (name) => { console.log(name) } test('Jerry')
規則二:如果參數隻有一個,可以不加括號,如果沒有參數或者參數多於一個就需要加括號
例子:
const test = name => { console.log(name) } test('Jerry') const test2 = (name1, name2) => { console.log(name1 + ' and ' + name2) } test2('Tom', 'Jerry')
規則三:如果函數體隻有一句話,可以不加花括號
例子:
const test = name => console.log(name)
規則四:如果函數體沒有括號,可以不寫return,箭頭函數會幫你return
例子:
const add = (p1, p2) => p1 + p2 add(10, 25)
記住:函數體的花括號與return關鍵字同在。
從以上的例子我們可以看出,箭頭函數對常規函數的圓括號和花括號都進行瞭簡化。除瞭這些簡化,箭頭函數對於常規函數最大的優化之處在於this。
二、理解常規函數中this
在探討箭頭函數對於this的優化之前,我們先得明白this究竟是什麼,以及它是如何使用的。this是使用call方法調用函數時傳遞的第一個參數,它可以在函數調用時修改,在函數沒有調用的時候,this的值是無法確定。
如果沒有使用過call方法來調用函數的話,上面的對於this的定義可能不太明白。那麼我們需要先理解函數調用的兩種方法。
1. 純粹的函數調用
第一種方法最常見,例子如下:
function test(name) { console.log(name) console.log(this) } test('Jerry') //調用函數
這種方法我們使用最多,但是這種函數調用方法隻是一種簡寫,它完整的寫法是下面這樣的:
function test(name) { console.log(name) console.log(this) } test.call(undefined, 'Tom')
註意到上面調用函數的call方法瞭嗎?call方法接收的第一個參數就是this,這裡我們傳瞭一個undefined。那麼,依據定義,函數執行瞭之後打出來的this會是undefined嗎?也不是。
如果你傳的 context 就 null 或者 undefined,那麼 window 對象就是默認的 context(嚴格模式下默認 context 是 undefined)。
所以這裡我們打出來的this是Window對象。
2. 對象中函數的調用
直接看例子:
const obj = { name: 'Jerry', greet: function() { console.log(this.name) } } obj.greet() //第一種調用方法 obj.greet.call(obj) //第二種調用方法
例子裡第一種調用方法隻是第二種調用方法的語法糖,第二種才是完整的調用方法,而且第二種方法厲害的地方在於它可以手動指定this。
手動指定this的例子:
const obj = { name: 'Jerry', greet: function() { console.log(this.name) } } obj.greet.call({name: 'Spike'}) //打出來的是 Spike
從上面的例子我們看到greet函數執行時this,已經被我們改過瞭。
3. 構造函數中this
構造函數裡的this稍微有點特殊,每個構造函數在new之後都會返回一個對象,這個對象就是this,也就是context上下文。
例子:
function Test() { this.name = 'Tom' } let p = new Test() console.log(typeof p) //object console.log(p.name) // Tom
4. window.setTimeout()和window.setInterval()中函數的調用
window.setTimeout()和window.setInterval()的函數中的this有些特殊,裡面的this默認是window對象。
簡單總結一下:函數完整的調用方法是使用call方法,包括test.call(context, name)和obj.greet.call(context,name),這裡的context就是函數調用時的上下文,也就是this,隻不過這個this是可以通過call方法來修改的;構造函數稍微特殊一點,它的this直接指向new之後返回的對象;window.setTimeout()和window.setInterval()默認的是this是window對象。
三、理解箭頭函數中的this
上面關於this講瞭很多,this是函數用call方法調用時傳遞的第一個參數,而且它還可以手動更改,這樣要確定this的值就太麻煩瞭。不過,箭頭函數的出現給我們確定this幫瞭一些忙。
1. 箭頭函數的特性一:默認綁定外層this
上面提到:this的值是可以用call方法修改的,而且隻有在調用的時候我們才能確定this的值。而當我們使用箭頭函數的時候,箭頭函數會默認幫我們綁定外層this的值,所以在箭頭函數中this的值和外層的this是一樣的。
不使用箭頭函數例子:
const obj = { a: function() { console.log(this) } } obj.a() //打出的是obj對象
使用箭頭函數的例子:
const obj = { a: () => { console.log(this) } } obj.a() //打出來的是window
在使用箭頭函數的例子裡,因為箭頭函數默認不會使用自己的this,而是會和外層的this保持一致,最外層的this就是window對象。
2. 箭頭函數的特性二:不能用call方法修改裡面的this
這個也很好理解,我們之前一直在說,函數的this可以用call方法來手動指定,而為瞭減少this的復雜性,箭頭函數無法用call方法來指定this。
例子:
const obj = { a: () => { console.log(this) } } obj.a.call('123') //打出來的結果依然是window對象
因為上文我們說到window.setTimeout()中函數裡的this默認是window,我們也可以通過箭頭函數使它的this和外層的this保持一致:
window.setTimeout()的例子:
const obj = { a: function() { console.log(this) window.setTimeout(() => { console.log(this) }, 1000) } } obj.a.call(obj) //第一個this是obj對象,第二個this還是obj對象
想必大傢明白瞭,函數obj.a沒有使用箭頭函數,因為它的this還是obj,而setTimeout裡的函數使用瞭箭頭函數,所以它會和外層的this保持一致,也是obj;如果setTimeout裡的函數沒有使用箭頭函數,那麼它打出來的應該是window對象。
四、多層對象嵌套裡函數的this
這裡是筆者在學習時遇到的一點疑惑。箭頭函數裡的this是和外層保持一致的,但是如果這個外層有好多層,那它是和哪層保持一致呢?
直接上例子:
const obj = { a: function() { console.log(this) }, b: { c: function() {console.log(this)} } } obj.a() // 打出的是obj對象, 相當於obj.a.call(obj) obj.b.c() //打出的是obj.b對象, 相當於obj.b.c.call(obj.b)
上面的代碼都符合直覺,接下來把obj.b.c對應的函數換成箭頭函數,結果如下:
const obj = { a: function() { console.log(this) }, b: { c: () => {console.log(this)} } } obj.a() //沒有使用箭頭函數打出的是obj obj.b.c() //打出的是window對象!!
obj.a調用後打出來的是obj對象,而obj.b.c調用後打出的是window對象而非obj,這表示多層對象嵌套裡箭頭函數裡this是和最最外層保持一致的。
上面的內容就是筆者學習箭頭函數中梳理出來的知識點,如有錯誤,請批評指正!這是我在掘金上寫的第三篇文章,感謝閱讀!
本文參考:this 的值到底是什麼?一次說清楚
總結
到此這篇關於JS中箭頭函數與this的寫法和理解的文章就介紹到這瞭,更多相關JS箭頭函數與this內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 一文搞懂JavaScript中的this綁定規則
- Vue自定義指令中無法獲取this的問題及解決
- JavaScript三大變量聲明詳析
- JavaScript進階知識點作用域詳解
- JavaScript中的this例題實戰總結詳析