關(guān)于vue data中的this指向問題
vue data的this指向
在data里定義Object類型的變量時(shí),會(huì)發(fā)現(xiàn)Object中訪問不到vue的this屬性。
例如:
export default { ? data(){ ? ? return { ? ? ? a: "123", ? ? ? b: { ? ? ? ? c: this.a ? ? ? } ? ? }; ? }, ? created() { ? ? console.log("b: ", this.b.c); // undefined ? } }
想在b中訪問this.a的數(shù)據(jù),直接訪問會(huì)返回undefined,因?yàn)檫@時(shí)c中的this指向的是b。
這種情況可以用到Object的get屬性進(jìn)行屬性定義。
例如:
export default { ? data(){ ? ? return { ? ? ? a: "123", ? ? ? b: { ? ? ? ? _target: () => this, ? ? ? ? get target() { ? ? ? ? ? return this._target(); ? ? ? ? }, ? ? ? ? get c() { ? ? ? ? ? return this.target.a; ? ? ? ? }, ? ? ? }, ? ? }; ? }, ? created() { ? ? console.log("b: ", this.b.c); // 123 ? } }
此處將this映射到了Object變量內(nèi)部,然后通過get的形式定義屬性并獲取。
當(dāng)get定義的屬性所依賴的屬性的值發(fā)生改變時(shí),get定義的屬性的值也將發(fā)生改變。
例如:
export default { ? data(){ ? ? return { ? ? ? a: "123", ? ? ? b: { ? ? ? ? _target: () => this, ? ? ? ? get target() { ? ? ? ? ? return this._target(); ? ? ? ? }, ? ? ? ? get c() { ? ? ? ? ? return this.target.a; ? ? ? ? }, ? ? ? ? d: 123, ? ? ? ? get e() { ? ? ? ? ? return `依賴于d的值, 會(huì)同步發(fā)生改變, d的值為: ${this.d}`; ? ? ? ? } ? ? ? }, ? ? }; ? }, ? created() { ? ? console.log("b: ", this.b.c); // 123 ? ? console.log("e: ", this.b.e); // e: ?依賴于d的值, 會(huì)同步發(fā)生改變, d的值為: 123 c: 123 ? ? setTimeout(() => { ? ? ? this.b.d = 456; ? ? ? console.log("e: ", this.b.e); // e: ?依賴于d的值, 會(huì)同步發(fā)生改變, d的值為: 456 c: 123 ? ? }, 1000); ? ? setTimeout(() => { ? ? ? this.a = "456"; ? ? ? console.log("e: ", this.b.e); // e: ?依賴于d的值, 會(huì)同步發(fā)生改變, d的值為: 456 c: 456 ? ? }, 2000); ? } }
當(dāng)前方法更像是一種深度計(jì)算屬性(computed),會(huì)隨著所依賴的項(xiàng)發(fā)生改變而改變。
vue關(guān)于this指向的重要原則
在學(xué)習(xí)js的時(shí)候,偶爾會(huì)涉及到this的指向問題。大部分情況下,在一個(gè)函數(shù)中,誰調(diào)用這個(gè)函數(shù),this就指向誰。
在Vue中,this的指向卻顯得尤為重要。本節(jié)博客將為大家解釋Vue中this的指向問題,同時(shí)告訴讀者,為什么this的指向在Vue中非常重要,以及我們?cè)谄綍r(shí)寫Vue代碼時(shí)需要注意的相關(guān)內(nèi)容。
vue底層的相關(guān)原理
1.1 MVVM模型的復(fù)習(xí)
Vue的設(shè)計(jì)收到了MVVM模型的影響,在看this指向問題前,我想帶讀者們復(fù)習(xí)一下MVVM模型的相關(guān)知識(shí)。
M
:Model模型,對(duì)應(yīng)的是data中的數(shù)據(jù);V
:View視圖,對(duì)應(yīng)的是模板,也就是頁面結(jié)構(gòu);VM
:視圖模型,對(duì)應(yīng)的是Vue實(shí)例對(duì)象。
這里用一個(gè)html文件給大家劃分一下具體結(jié)構(gòu):
1.2 通過差值語法看vm的屬性
所有vm中的屬性,利用差值語法都可以看到。
為了測試,我們先看看vm是什么。此處,我們先打印一下this,可以看到此時(shí)的this是Vue。
準(zhǔn)確來說使我們創(chuàng)建的Vue實(shí)例。這里面的所有屬性都可以通過插值語法看到。
為了驗(yàn)證上面說的話,現(xiàn)在我利用差值語法隨意看Vue實(shí)例對(duì)象中的一些東西:
1.3 為什么差值語法可以看到vm的內(nèi)部屬性
==因?yàn)樵赩ue中,this指向的是vm實(shí)例對(duì)象Vue。==所以可以利用this看到vm的所有屬性。希望讀者朋友們可以牢記這一點(diǎn)。
記住這一點(diǎn)在時(shí)時(shí)刻刻的應(yīng)用中:我們不要輕易的改變this的指向,如若改變,this不再是vm,頁面上的元素將無法正常被渲染。
這里給大家看一個(gè)例子:
這段代碼的需求是,在 頁面中寫出姓和名,讓Vue幫我們合成姓名。并且在我們修改姓或者名后停頓1s后再幫我們合成。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../vue.js"></script> </head> <body> <div id="root"> 姓:<input type="text" v-model="firstName"><br> 名:<input type="text" v-model="lastName"><br> 全名:<span>{{ fullName }}</span> </div> <script> new Vue({ el: '#root', data: { firstName: '張', lastName: '三', fullName: '' }, watch: { firstName(newValue, oldValue) { setTimeout(() => { this.fullName = newValue + this.lastName console.log(this) }, 1000) }, lastName(newValue, oldValue) { setTimeout(() => { this.fullName = this.firstName + newValue console.log(this) }, 1000) } } }) </script> </body> </html>
上述代碼是沒有什么問題的。并且在定時(shí)器中,使用箭頭函數(shù),打印出來的this都是vue實(shí)例
原因:箭頭函數(shù)中的this指向它的外層調(diào)用者。
現(xiàn)在看一個(gè)反例:我們把箭頭函數(shù)改成普通函數(shù),則會(huì)出現(xiàn)問題:
<body> <div id="root"> 姓:<input type="text" v-model="firstName"><br> 名:<input type="text" v-model="lastName"><br> 全名:<span>{{ fullName }}</span> </div> <script> new Vue({ el: '#root', data: { firstName: '張', lastName: '三', fullName: '' }, watch: { firstName(newValue, oldValue) { setTimeout(() => { this.fullName = newValue + this.lastName console.log(this) }, 1000) }, // lastName(newValue, oldValue) { // setTimeout(() => { // this.fullName = this.firstName + newValue // console.log(this) // }, 1000) // } // 這是一個(gè)錯(cuò)誤寫法,因?yàn)樗淖兞藅his的指向。它的this是window。那么就沒辦法讀到vue中的數(shù)據(jù)了 lastName(newValue, oldValue) { setTimeout(function() { this.fullName = this.firstName + newValue console.log(this) }, 1000) } } }) </script>
沒辦法正常運(yùn)行并且,this打印出來的是window:
==原因:普通函數(shù)中的this指向它的直接調(diào)用者。
==由于定時(shí)器的this指向的是window。此時(shí)此刻,改變了this的指向,所以會(huì)報(bào)錯(cuò)。
心得
1.所被Vue管理的函數(shù),最好寫成普通函數(shù)。這樣的this指向?qū)嵗龑?duì)象;
2.所有不被Vue所管理的函數(shù)(定時(shí)器,ajax,回調(diào))最好寫成箭頭函數(shù),這樣this依舊指向Vue或者組件的實(shí)例對(duì)象。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue+vue-validator 表單驗(yàn)證功能的實(shí)現(xiàn)代碼
這篇文章主要介紹了vue+vue-validator 表單驗(yàn)證功能的實(shí)現(xiàn)代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-11-11淺談ElementUI el-select 數(shù)據(jù)過多解決辦法
下拉框的選項(xiàng)很多,上萬個(gè)選項(xiàng)甚至更多,這個(gè)時(shí)候如果全部把數(shù)據(jù)放到下拉框中渲染出來,瀏覽器會(huì)卡死,體驗(yàn)會(huì)特別不好,本文主要介紹了ElementUI el-select 數(shù)據(jù)過多解決辦法,感興趣的可以了解一下2021-09-09Vue.js項(xiàng)目在apache服務(wù)器部署問題解決
本文主要介紹了Vue.js項(xiàng)目在apache服務(wù)器部署問題解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06vue 監(jiān)聽input輸入事件(oninput)的示例代碼支持模糊查詢
這篇文章主要介紹了vue 監(jiān)聽input輸入事件(oninput)支持模糊查詢,比如說表格模糊查詢,實(shí)現(xiàn)一邊輸入,一邊過濾數(shù)據(jù),本文通過示例代碼給大家詳細(xì)講解,需要的朋友可以參考下2023-02-02vue用h()函數(shù)創(chuàng)建Vnodes的實(shí)現(xiàn)
Vue提供了一個(gè)h()函數(shù)用于創(chuàng)建vnodes,本文就來介紹一下vue用h()函數(shù)創(chuàng)建Vnodes的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01Vue3自動(dòng)引入組件與組件庫的方法實(shí)例
關(guān)于vue?組件還是非常好用的,真正掌握預(yù)計(jì)需要一段時(shí)間,下面這篇文章主要給大家介紹了關(guān)于Vue3自動(dòng)引入組件與組件庫的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-10-10