Vue箭頭函數(shù)與普通函數(shù)的正確使用及說(shuō)明
在 Vue 項(xiàng)目中,你是否遇到過(guò)這樣的場(chǎng)景:
明明寫(xiě)了正確的邏輯,卻因?yàn)橛缅e(cuò)函數(shù)類(lèi)型,導(dǎo)致this.msg拿不到值、點(diǎn)擊事件不生效?其實(shí),這大多是箭頭函數(shù)與普通函數(shù)的this指向差異在 “搞鬼”。
本文不堆砌理論,而是從實(shí)際開(kāi)發(fā)痛點(diǎn)出發(fā),結(jié)合 Vue 2/3 的不同場(chǎng)景,帶你搞懂兩種函數(shù)的用法邊界,徹底避免這類(lèi)低級(jí)錯(cuò)誤。
一、先解決核心困惑:為什么用錯(cuò)函數(shù)會(huì)出問(wèn)題?
Vue 中函數(shù)報(bào)錯(cuò)的根源,90% 都和this指向有關(guān)。
箭頭函數(shù)與普通函數(shù)的本質(zhì)差異,就體現(xiàn)在this的綁定規(guī)則上 —— 這是我們判斷 “該用哪種函數(shù)” 的唯一核心標(biāo)準(zhǔn)。
1. 一張表分清兩種函數(shù)的關(guān)鍵差異
| 對(duì)比維度 | 普通函數(shù)(function) | 箭頭函數(shù)(() => {}) |
|---|---|---|
| this綁定 | 動(dòng)態(tài):誰(shuí)調(diào)用,this就指向誰(shuí) | 靜態(tài):定義時(shí)繼承外層非箭頭函數(shù)的this |
| 適用場(chǎng)景 | 需要訪問(wèn) Vue 實(shí)例(data/props)時(shí) | 無(wú)需綁定實(shí)例,需固定this時(shí) |
| 能否當(dāng)構(gòu)造函數(shù) | 能(new Function()) | 不能(報(bào)錯(cuò)) |
| 能否用arguments | 能(獲取所有實(shí)參) | 不能(需用...rest參數(shù)) |
| 語(yǔ)法復(fù)雜度 | 需寫(xiě)function,代碼稍長(zhǎng) | 省略function,簡(jiǎn)潔(僅匿名) |
2. 最關(guān)鍵的this指向?qū)Ρ龋ǜ?Vue 場(chǎng)景示例)
- 普通函數(shù):
this是 “跟著調(diào)用者走” 的。比如 Vue 組件的methods里,函數(shù)由組件實(shí)例(vm)調(diào)用,所以this自然指向vm,能拿到this.data里的內(nèi)容。 - 箭頭函數(shù):
this是 “跟著定義環(huán)境走” 的。它不會(huì)自己綁定this,而是 “抄” 外層非箭頭函數(shù)的this。如果外層沒(méi)有非箭頭函數(shù),this就會(huì)變成window(瀏覽器)或undefined(嚴(yán)格模式)。 - 舉個(gè)直觀的例子:
<script>
export default {
data() {
return { name: "Vue" };
},
created() {
// 普通函數(shù):由this(組件實(shí)例)調(diào)用,this指向?qū)嵗?
const normalFunc = function() {
console.log(this.name); // 輸出"Vue"
};
normalFunc.call(this); // 主動(dòng)綁定this為組件實(shí)例
// 箭頭函數(shù):繼承外層created的this(組件實(shí)例)
const arrowFunc = () => {
console.log(this.name); // 輸出"Vue"
};
arrowFunc(); // 無(wú)需綁定,this已固定
// 注意:如果箭頭函數(shù)外層是普通函數(shù),this會(huì)變
const outerFunc = function() {
const innerArrow = () => {
console.log(this.name); // 這里的this是outerFunc的this(若未綁定則為window)
};
innerArrow();
};
outerFunc(); // 輸出undefined(因?yàn)閛uterFunc的this是window)
}
};
</script>
二、Vue 2/3 通用場(chǎng)景:哪些地方必須用普通函數(shù)?
這些場(chǎng)景的核心需求是 “訪問(wèn) Vue 實(shí)例”,箭頭函數(shù)會(huì)直接導(dǎo)致this失效,哪怕代碼能運(yùn)行,也會(huì)埋下隱患。
1.methods中的事件處理函數(shù)(絕對(duì)不能用箭頭函數(shù))
methods里的函數(shù)要綁定到模板事件(如@click、@input),Vue 會(huì)自動(dòng)把函數(shù)的this綁定到組件實(shí)例。
如果用箭頭函數(shù),this會(huì)繼承methods定義時(shí)的外層環(huán)境(通常是window),導(dǎo)致無(wú)法訪問(wèn)實(shí)例數(shù)據(jù)。
- 錯(cuò)誤示范(點(diǎn)擊按鈕無(wú)反應(yīng),控制臺(tái)報(bào)錯(cuò)):
<template>
<button @click="changeName">修改名稱(chēng)</button>
<p>{{ name }}</p>
</template>
<script>
export default {
data() {
return { name: "初始名稱(chēng)" };
},
methods: {
// 錯(cuò)誤:箭頭函數(shù)的this不是組件實(shí)例
changeName: () => {
this.name = "修改后名稱(chēng)"; // 報(bào)錯(cuò):Cannot set property 'name' of undefined
}
}
};
</script>
- 正確示范(點(diǎn)擊按鈕正常修改):
methods: {
// 普通函數(shù):this指向組件實(shí)例
changeName() {
this.name = "修改后名稱(chēng)"; // 正常生效
}
}
2.computed計(jì)算屬性(必須用普通函數(shù))
computed需要依賴(lài)data或props計(jì)算值,普通函數(shù)能確保this指向?qū)嵗^函數(shù)會(huì)導(dǎo)致依賴(lài)無(wú)法讀取。
- 正確寫(xiě)法:
computed: {
fullName() {
// 普通函數(shù):this能拿到firstName和lastName
return `${this.firstName} ${this.lastName}`;
}
}
3.watch監(jiān)聽(tīng)器(推薦用普通函數(shù))
watch需要在數(shù)據(jù)變化時(shí)執(zhí)行邏輯(如修改其他數(shù)據(jù)、調(diào)用接口),普通函數(shù)的this能直接操作實(shí)例,箭頭函數(shù)會(huì)導(dǎo)致邏輯失效。
- 正確寫(xiě)法:
watch: {
// 監(jiān)聽(tīng)name變化,更新日志
name(newVal, oldVal) {
this.log = `名稱(chēng)從${oldVal}變成${newVal}`; // this指向?qū)嵗?,正常更?
}
}
4. 生命周期鉤子(Vue 2 推薦普通函數(shù),Vue 3setup外同)
Vue 2 的created、mounted等鉤子,雖然用箭頭函數(shù) “看似能運(yùn)行”(因?yàn)殂^子的this是實(shí)例,箭頭函數(shù)會(huì)繼承),但不符合 Vue 設(shè)計(jì)規(guī)范,且后續(xù)維護(hù)者容易誤解this來(lái)源。Vue 3 的Options API(非setup)場(chǎng)景同理。
- 推薦寫(xiě)法:
// Vue 2 / Vue 3 Options API
export default {
mounted() {
this.initData(); // 普通函數(shù):this指向?qū)嵗?,調(diào)用methods方法
},
methods: {
initData() {
// 初始化邏輯
}
}
};
三、Vue 2/3 通用場(chǎng)景:哪些地方推薦用箭頭函數(shù)?
這些場(chǎng)景不需要訪問(wèn) Vue 實(shí)例,或需要固定this指向,箭頭函數(shù)能讓代碼更簡(jiǎn)潔,避免手動(dòng)綁定this的麻煩。
1. 數(shù)組方法回調(diào)(map/filter/forEach等)
數(shù)組方法的回調(diào)函數(shù)如果用普通函數(shù),this會(huì)指向window(非嚴(yán)格模式),需要用that = this或bind(this)綁定;用箭頭函數(shù)能直接繼承外層實(shí)例的this,代碼更簡(jiǎn)潔。
- 對(duì)比示例:
methods: {
handleList() {
const list = [1, 2, 3];
// 普通函數(shù):需要手動(dòng)保存this
const normalResult = list.map(function(item) {
return item * this.multiplier; // 這里的this是window,需綁定
}.bind(this)); // 綁定this為組件實(shí)例
// 箭頭函數(shù):自動(dòng)繼承外層this(handleList的this是實(shí)例)
const arrowResult = list.map(item => {
return item * this.multiplier; // 直接使用實(shí)例的multiplier
});
console.log(arrowResult); // 正確輸出:[2,4,6](若multiplier=2)
},
data() {
return { multiplier: 2 };
}
}
2. 異步請(qǐng)求回調(diào)(axios/Promise)
異步操作的回調(diào)函數(shù)(如接口請(qǐng)求成功 / 失敗后),普通函數(shù)的this會(huì)指向回調(diào)的調(diào)用者(如axios內(nèi)部對(duì)象),而非 Vue 實(shí)例;箭頭函數(shù)能繼承外層實(shí)例的this,方便后續(xù)操作數(shù)據(jù)。
- 正確示例(接口請(qǐng)求后更新數(shù)據(jù)):
methods: {
fetchUser() {
// 外層this是組件實(shí)例
axios.get("/api/user")
.then(res => {
// 箭頭函數(shù):this指向?qū)嵗?,更新data
this.userInfo = res.data;
})
.catch(err => {
// 箭頭函數(shù):this指向?qū)嵗?,更新錯(cuò)誤信息
this.errorMsg = err.message;
});
}
}
3. Vue 3setup函數(shù)內(nèi)(全部用箭頭函數(shù))
Vue 3 的Composition API中,setup函數(shù)沒(méi)有this(this指向undefined),所有函數(shù)定義都推薦用箭頭函數(shù),避免依賴(lài)this導(dǎo)致混亂。
- 示例:
<script setup>
import { ref } from "vue";
const count = ref(0);
// 箭頭函數(shù):無(wú)需考慮this,直接操作ref
const increment = () => {
count.value++; // 正確修改ref值
};
// 異步請(qǐng)求示例
const fetchData = () => {
axios.get("/api/data")
.then(res => {
// 直接操作ref或reactive數(shù)據(jù)
});
};
</script>
<template>
<button @click="increment">{{ count }}</button>
</template>
四、避坑指南:90% 開(kāi)發(fā)者會(huì)犯的 3 個(gè)錯(cuò)誤
錯(cuò)誤 1:在methods中混用箭頭函數(shù)和普通函數(shù)
有些開(kāi)發(fā)者為了 “簡(jiǎn)潔”,在methods中部分函數(shù)用箭頭函數(shù),導(dǎo)致部分功能失效。記?。?code>methods里所有函數(shù)都必須用普通函數(shù)。
錯(cuò)誤 2:Vue 2 生命周期鉤子用箭頭函數(shù)
雖然 Vue 2 中created: () => { this.init() }能運(yùn)行,但這是 “巧合”—— 如果后續(xù)修改外層代碼(如把鉤子函數(shù)嵌套到其他函數(shù)中),this會(huì)立即失效。
錯(cuò)誤 3:Vue 3setup中用普通函數(shù)
setup中沒(méi)有this,普通函數(shù)的this是undefined,如果在普通函數(shù)中用this,會(huì)直接報(bào)錯(cuò)。比如:
<script setup>
// 錯(cuò)誤:setup中普通函數(shù)的this是undefined
const wrongFunc = function() {
console.log(this.count); // 報(bào)錯(cuò):Cannot read property 'count' of undefined
};
</script>
五、總結(jié):1 個(gè)判斷標(biāo)準(zhǔn),搞定所有場(chǎng)景
遇到函數(shù)定義時(shí),不用記復(fù)雜規(guī)則,只需問(wèn)自己:這個(gè)函數(shù)需要訪問(wèn) Vue 實(shí)例的data/props/methods嗎?
- 是 → 用普通函數(shù)(如
methods、computed、watch); - 否 → 用箭頭函數(shù)(如數(shù)組回調(diào)、異步回調(diào)、Vue 3
setup)。
掌握這個(gè)標(biāo)準(zhǔn),就能徹底避免 Vue 中因函數(shù)類(lèi)型用錯(cuò)導(dǎo)致的this問(wèn)題,讓代碼邏輯更清晰、更易維護(hù)。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解在vue使用weixin-js-sdk常見(jiàn)使用方法
這篇文章主要介紹了 詳解在vue使用weixin-js-sdk常見(jiàn)使用方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05
vue-resource:jsonp請(qǐng)求百度搜索的接口示例
今天小編就為大家分享一篇vue-resource:jsonp請(qǐng)求百度搜索的接口示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11
學(xué)習(xí)Vue框架中必掌握的重點(diǎn)知識(shí)
這篇文章主要介紹了學(xué)習(xí)Vue中必掌握的重點(diǎn)知識(shí),想了解vue的同學(xué)可以參考下2021-04-04
詳解基于 Nuxt 的 Vue.js 服務(wù)端渲染實(shí)踐
這篇文章主要介紹了詳解基于 Nuxt 的 Vue.js 服務(wù)端渲染實(shí)踐,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10
Vue.js 帶下拉選項(xiàng)的輸入框(Textbox with Dropdown)組件
這篇文章主要介紹了Vue.js 帶下拉選項(xiàng)的輸入框(Textbox with Dropdown)組件,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04

