JS中箭頭函數(shù)與this的寫(xiě)法和理解
前言
JavaScript在ES6語(yǔ)法中新增了箭頭函數(shù),相較于傳統(tǒng)函數(shù),箭頭函數(shù)不僅更加簡(jiǎn)潔,而且在this方面進(jìn)行了改進(jìn)。this作為JavaScript中比較詭異的存在,許多文章對(duì)于this的解釋也不盡相同,本篇文章試圖厘清JS中函數(shù)與this的關(guān)系。
一、JS中函數(shù)的寫(xiě)法
1.常規(guī)函數(shù)的寫(xiě)法
在ES6語(yǔ)法之前,JS中的函數(shù)由function關(guān)鍵字、params參數(shù)和被花括號(hào)包裹的函數(shù)體組成。為了與后面說(shuō)到的箭頭函數(shù)相區(qū)別,我們先把這樣的函數(shù)叫做常規(guī)函數(shù),常規(guī)函數(shù)既可以用聲明式寫(xiě)法也可以用賦值式寫(xiě)法。例子:
function test(name) { //聲明式寫(xiě)法
console.log(name)
}
test('Jerry')
let test2 = function(name) { //賦值式寫(xiě)法
console.log(name)
}
test2('Tom')
2. 箭頭函數(shù)的寫(xiě)法
ES6箭頭函數(shù)的引入,使函數(shù)的寫(xiě)法變的更加簡(jiǎn)潔,但在書(shū)寫(xiě)上要遵循一定的規(guī)則。
規(guī)則一:箭頭函數(shù)只能用賦值式寫(xiě)法,不能用聲明式寫(xiě)法
例子:
const test = (name) => {
console.log(name)
}
test('Jerry')
規(guī)則二:如果參數(shù)只有一個(gè),可以不加括號(hào),如果沒(méi)有參數(shù)或者參數(shù)多于一個(gè)就需要加括號(hào)
例子:
const test = name => {
console.log(name)
}
test('Jerry')
const test2 = (name1, name2) => {
console.log(name1 + ' and ' + name2)
}
test2('Tom', 'Jerry')
規(guī)則三:如果函數(shù)體只有一句話,可以不加花括號(hào)
例子:
const test = name => console.log(name)
規(guī)則四:如果函數(shù)體沒(méi)有括號(hào),可以不寫(xiě)return,箭頭函數(shù)會(huì)幫你return
例子:
const add = (p1, p2) => p1 + p2 add(10, 25)
記?。汉瘮?shù)體的花括號(hào)與return關(guān)鍵字同在。
從以上的例子我們可以看出,箭頭函數(shù)對(duì)常規(guī)函數(shù)的圓括號(hào)和花括號(hào)都進(jìn)行了簡(jiǎn)化。除了這些簡(jiǎn)化,箭頭函數(shù)對(duì)于常規(guī)函數(shù)最大的優(yōu)化之處在于this。
二、理解常規(guī)函數(shù)中this
在探討箭頭函數(shù)對(duì)于this的優(yōu)化之前,我們先得明白this究竟是什么,以及它是如何使用的。this是使用call方法調(diào)用函數(shù)時(shí)傳遞的第一個(gè)參數(shù),它可以在函數(shù)調(diào)用時(shí)修改,在函數(shù)沒(méi)有調(diào)用的時(shí)候,this的值是無(wú)法確定。
如果沒(méi)有使用過(guò)call方法來(lái)調(diào)用函數(shù)的話,上面的對(duì)于this的定義可能不太明白。那么我們需要先理解函數(shù)調(diào)用的兩種方法。
1. 純粹的函數(shù)調(diào)用
第一種方法最常見(jiàn),例子如下:
function test(name) {
console.log(name)
console.log(this)
}
test('Jerry') //調(diào)用函數(shù)
這種方法我們使用最多,但是這種函數(shù)調(diào)用方法只是一種簡(jiǎn)寫(xiě),它完整的寫(xiě)法是下面這樣的:
function test(name) {
console.log(name)
console.log(this)
}
test.call(undefined, 'Tom')
注意到上面調(diào)用函數(shù)的call方法了嗎?call方法接收的第一個(gè)參數(shù)就是this,這里我們傳了一個(gè)undefined。那么,依據(jù)定義,函數(shù)執(zhí)行了之后打出來(lái)的this會(huì)是undefined嗎?也不是。
如果你傳的 context 就 null 或者 undefined,那么 window 對(duì)象就是默認(rèn)的 context(嚴(yán)格模式下默認(rèn) context 是 undefined)。
所以這里我們打出來(lái)的this是Window對(duì)象。
2. 對(duì)象中函數(shù)的調(diào)用
直接看例子:
const obj = {
name: 'Jerry',
greet: function() {
console.log(this.name)
}
}
obj.greet() //第一種調(diào)用方法
obj.greet.call(obj) //第二種調(diào)用方法
例子里第一種調(diào)用方法只是第二種調(diào)用方法的語(yǔ)法糖,第二種才是完整的調(diào)用方法,而且第二種方法厲害的地方在于它可以手動(dòng)指定this。
手動(dòng)指定this的例子:
const obj = {
name: 'Jerry',
greet: function() {
console.log(this.name)
}
}
obj.greet.call({name: 'Spike'}) //打出來(lái)的是 Spike
從上面的例子我們看到greet函數(shù)執(zhí)行時(shí)this,已經(jīng)被我們改過(guò)了。
3. 構(gòu)造函數(shù)中this
構(gòu)造函數(shù)里的this稍微有點(diǎn)特殊,每個(gè)構(gòu)造函數(shù)在new之后都會(huì)返回一個(gè)對(duì)象,這個(gè)對(duì)象就是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()中函數(shù)的調(diào)用
window.setTimeout()和window.setInterval()的函數(shù)中的this有些特殊,里面的this默認(rèn)是window對(duì)象。
簡(jiǎn)單總結(jié)一下:函數(shù)完整的調(diào)用方法是使用call方法,包括test.call(context, name)和obj.greet.call(context,name),這里的context就是函數(shù)調(diào)用時(shí)的上下文,也就是this,只不過(guò)這個(gè)this是可以通過(guò)call方法來(lái)修改的;構(gòu)造函數(shù)稍微特殊一點(diǎn),它的this直接指向new之后返回的對(duì)象;window.setTimeout()和window.setInterval()默認(rèn)的是this是window對(duì)象。
三、理解箭頭函數(shù)中的this
上面關(guān)于this講了很多,this是函數(shù)用call方法調(diào)用時(shí)傳遞的第一個(gè)參數(shù),而且它還可以手動(dòng)更改,這樣要確定this的值就太麻煩了。不過(guò),箭頭函數(shù)的出現(xiàn)給我們確定this幫了一些忙。
1. 箭頭函數(shù)的特性一:默認(rèn)綁定外層this
上面提到:this的值是可以用call方法修改的,而且只有在調(diào)用的時(shí)候我們才能確定this的值。而當(dāng)我們使用箭頭函數(shù)的時(shí)候,箭頭函數(shù)會(huì)默認(rèn)幫我們綁定外層this的值,所以在箭頭函數(shù)中this的值和外層的this是一樣的。
不使用箭頭函數(shù)例子:
const obj = {
a: function() { console.log(this) }
}
obj.a() //打出的是obj對(duì)象
使用箭頭函數(shù)的例子:
const obj = {
a: () => {
console.log(this)
}
}
obj.a() //打出來(lái)的是window
在使用箭頭函數(shù)的例子里,因?yàn)榧^函數(shù)默認(rèn)不會(huì)使用自己的this,而是會(huì)和外層的this保持一致,最外層的this就是window對(duì)象。
2. 箭頭函數(shù)的特性二:不能用call方法修改里面的this
這個(gè)也很好理解,我們之前一直在說(shuō),函數(shù)的this可以用call方法來(lái)手動(dòng)指定,而為了減少this的復(fù)雜性,箭頭函數(shù)無(wú)法用call方法來(lái)指定this。
例子:
const obj = {
a: () => {
console.log(this)
}
}
obj.a.call('123') //打出來(lái)的結(jié)果依然是window對(duì)象
因?yàn)樯衔奈覀冋f(shuō)到window.setTimeout()中函數(shù)里的this默認(rèn)是window,我們也可以通過(guò)箭頭函數(shù)使它的this和外層的this保持一致:
window.setTimeout()的例子:
const obj = {
a: function() {
console.log(this)
window.setTimeout(() => {
console.log(this)
}, 1000)
}
}
obj.a.call(obj) //第一個(gè)this是obj對(duì)象,第二個(gè)this還是obj對(duì)象
想必大家明白了,函數(shù)obj.a沒(méi)有使用箭頭函數(shù),因?yàn)樗膖his還是obj,而setTimeout里的函數(shù)使用了箭頭函數(shù),所以它會(huì)和外層的this保持一致,也是obj;如果setTimeout里的函數(shù)沒(méi)有使用箭頭函數(shù),那么它打出來(lái)的應(yīng)該是window對(duì)象。
四、多層對(duì)象嵌套里函數(shù)的this
這里是筆者在學(xué)習(xí)時(shí)遇到的一點(diǎn)疑惑。箭頭函數(shù)里的this是和外層保持一致的,但是如果這個(gè)外層有好多層,那它是和哪層保持一致呢?
直接上例子:
const obj = {
a: function() { console.log(this) },
b: {
c: function() {console.log(this)}
}
}
obj.a() // 打出的是obj對(duì)象, 相當(dāng)于obj.a.call(obj)
obj.b.c() //打出的是obj.b對(duì)象, 相當(dāng)于obj.b.c.call(obj.b)
上面的代碼都符合直覺(jué),接下來(lái)把obj.b.c對(duì)應(yīng)的函數(shù)換成箭頭函數(shù),結(jié)果如下:
const obj = {
a: function() { console.log(this) },
b: {
c: () => {console.log(this)}
}
}
obj.a() //沒(méi)有使用箭頭函數(shù)打出的是obj
obj.b.c() //打出的是window對(duì)象??!
obj.a調(diào)用后打出來(lái)的是obj對(duì)象,而obj.b.c調(diào)用后打出的是window對(duì)象而非obj,這表示多層對(duì)象嵌套里箭頭函數(shù)里this是和最最外層保持一致的。
上面的內(nèi)容就是筆者學(xué)習(xí)箭頭函數(shù)中梳理出來(lái)的知識(shí)點(diǎn),如有錯(cuò)誤,請(qǐng)批評(píng)指正!這是我在掘金上寫(xiě)的第三篇文章,感謝閱讀!
總結(jié)
到此這篇關(guān)于JS中箭頭函數(shù)與this的寫(xiě)法和理解的文章就介紹到這了,更多相關(guān)JS箭頭函數(shù)與this內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- JavaScript中的普通函數(shù)和箭頭函數(shù)的區(qū)別和用法詳解
- 深入理解JavaScript中的箭頭函數(shù)
- JavaScript箭頭(arrow)函數(shù)詳解
- JavaScript箭頭函數(shù)中的this詳解
- 深入理解Javascript箭頭函數(shù)中的this
- 深入理解JavaScript 箭頭函數(shù)
- JavaScript箭頭函數(shù)的五種使用方法及三點(diǎn)注意事項(xiàng)
- JavaScript中箭頭函數(shù)與普通函數(shù)的區(qū)別詳解
- 一文徹底講通JavaScript普通函數(shù)與箭頭函數(shù)的區(qū)別
相關(guān)文章
關(guān)于JavaScript奇怪又實(shí)用的六個(gè)姿勢(shì)
這篇文章主要給大家介紹了關(guān)于JavaScript奇怪又實(shí)用的六個(gè)姿勢(shì),這些技巧和建議是我平常在開(kāi)發(fā)項(xiàng)目上會(huì)用到的,希望能讓大家學(xué)到知識(shí),需要的朋友可以參考下2021-10-10
基于Bootstrap的Java開(kāi)發(fā)問(wèn)題匯總(Spring MVC)
這篇文章主要為大家匯總了基于Bootstrap的Java開(kāi)發(fā)問(wèn)題,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01
淺談JavaScript 函數(shù)參數(shù)傳遞到底是值傳遞還是引用傳遞
下面小編就為大家?guī)?lái)一篇淺談JavaScript 函數(shù)參數(shù)傳遞到底是值傳遞還是引用傳遞。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-08-08
詳解如何在JavaScript中創(chuàng)建線性儀表圖
線性儀表圖表示顯示所需值的垂直或水平線性刻度,帶有顏色刻度以及單個(gè)或多個(gè)指針。本文將詳細(xì)講解如何利用JavaScript創(chuàng)建線性儀表圖,需要的可以參考一下2022-03-03
javascript實(shí)現(xiàn)動(dòng)態(tài)加載CSS
最近在做自己的小框架的按需加載模塊,那么就需要做到異步動(dòng)態(tài)加載css文件。仔細(xì)研究了一番,得到了如下解決方案,分享給大家。2015-01-01
drag-and-drop實(shí)現(xiàn)圖片瀏覽器預(yù)覽
chrome的drag and drop API,它能將本地的圖片放到瀏覽器中進(jìn)行預(yù)覽,猜想一下當(dāng)我們把圖片拖拽到瀏覽器里會(huì)發(fā)生什么事情,你的瀏覽器試圖打開(kāi)一個(gè)新的頁(yè)面并加載這個(gè)圖片。這篇文章給我們介紹drag-and-drop實(shí)現(xiàn)圖片瀏覽器預(yù)覽,需要的朋友可以參考下2015-08-08
IScroll5實(shí)現(xiàn)下拉刷新上拉加載的功能實(shí)例
本篇文章主要介紹了IScroll5實(shí)現(xiàn)下拉刷新上拉加載的功能實(shí)例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08

