談談因Vue.js引發(fā)關于getter和setter的思考
起因
當我打印出Vue實例下的data對象里的屬性時,發(fā)現(xiàn)了一個有趣的事情:

它的每個屬性都有兩個相對應的get和set方法,我覺的這是多此一舉的,于是去網(wǎng)上查了查Vue雙向綁定的實現(xiàn)原理,才發(fā)現(xiàn)它和Angular.js雙向綁定的實現(xiàn)原理完全不同,Angular是用的數(shù)據(jù)臟檢測,當Model發(fā)生變化,會檢測所有視圖是否綁定了相關數(shù)據(jù),再更改視圖。而Vue使用的發(fā)布訂閱模式,是點對點的綁定數(shù)據(jù)。
Vue的數(shù)據(jù)綁定只有兩個步驟,compile=>link。
我一直在想,vue是通過什么去監(jiān)聽用戶對Model的修改,直到我發(fā)現(xiàn)Vue的data里,每個屬性都有set和get屬性,我才明白過來。
在平時,我們創(chuàng)建一個對象,并修改它的屬性,是這樣的:
var obj = {
val:99
}
obj.val = 100;
console.log(obj.val)//100
沒有任何問題,但是如果要你去監(jiān)測,當我修改了這個對象的屬性時,要去做一些事,你會怎么做?
相關思考
這就要用到getter和setter了。
假設我現(xiàn)在要給一個碼農(nóng)對象添加一個name屬性,而且每次更新name屬性時,我要去完成一些事,我們可以這樣做:
var Coder = function() {
var that = this;
return {
get name(){
if(that.name){
return that.name
}
return '你還沒有取名'
},
set name(val){
console.log('你把名字修成了'+val)
that.name = val
}
}
}
var isMe = new Coder()
console.log(isMe.name)
isMe.name = '周神'
console.log(isMe.name)
console.log(isMe)
輸出:

你會發(fā)現(xiàn)這個對象和最上面的Vue中的data對象,打印出來的效果是一樣的,都擁有get和set屬性。
我們來一步步分析下上面的代碼,很有趣。
我們先創(chuàng)建一個對象字面量:
var Coder = function() {...}
再把this緩存一下:
var that = this;
接下來是最重要的,我們return了一個對象回去:
{
get name(){...},
set name(val){...}
}
顧名思義,get為取值,set為賦值,正常情況下,我們?nèi)≈岛唾x值是用obj.prop的方式,但是這樣做有一個問題,我如何知道對象的值改變了?所以就輪到set登場了。
你可以把get和set理解為function,當然,只是可以這么理解,這是完全不一樣的兩個東西。
接下來創(chuàng)建一個碼農(nóng)的實例,isMe;此時,isMe是沒有name屬性的,當我們調(diào)用isMe.name時,我們會進入到get name(){...}中,先判斷isMe是否有name屬性,答案是否定的,那麼就添加一個name屬性,并給它賦值:"你還沒有取名";如果有name屬性,那就返回name屬性。
看到這里你一定知道get怎么使用了,對,你可以把get看成一個取值的函數(shù),函數(shù)的返回值就是它拿到的值。
我感覺比較重要的是set屬性,當我給實例賦值:
isMe.name="周神"
此時,會進入set name(val){...};形參val就是我賦給name屬性的值,在這個函數(shù)里,我就可以做很多事了,比如雙向綁定!因為這個值的每次改變都必須經(jīng)過set,其他方式是改變不了它的,相當于一個萬能的監(jiān)聽器。
還有另一種方法可以實現(xiàn)這個功能。
ES5的對象原型有兩個新的屬性__defineGetter__和__defineSetter__ ,專門用來給對象綁定get和set。
可以這樣書寫:
var Coder = function() {
}
Coder.prototype.__defineGetter__('name', function() {
if (this.name) {
return this.name
}else{
return '你還沒有取名'
}
})
Coder.prototype.__defineSetter__('name', function(val) {
this.name = val
})
var isMe = new Coder()
console.log(isMe.name)
isMe.name = '周神'
console.log(isMe.name)
console.log(isMe)
效果是一樣的,建議使用下面這種方式,因為是在原型上書寫,所以可以繼承和重用。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流。
相關文章
vue實現(xiàn)的網(wǎng)易云音樂在線播放和下載功能案例
這篇文章主要介紹了vue實現(xiàn)的網(wǎng)易云音樂在線播放和下載功能,結(jié)合具體實例形式分析了網(wǎng)易云音樂相關接口調(diào)用與操作技巧,需要的朋友可以參考下2019-02-02
vue同一個瀏覽器登錄不同賬號數(shù)據(jù)覆蓋問題解決方案
同一個瀏覽器登錄不同賬號session一致,這就導致后面登錄的用戶數(shù)據(jù)會把前面登錄的用戶數(shù)據(jù)覆蓋掉,這個問題很常見,當前我這邊解決的就是同一個瀏覽器不同窗口只能登錄一個用戶,對vue同一個瀏覽器登錄不同賬號數(shù)據(jù)覆蓋問題解決方法感興趣的朋友一起看看吧2024-01-01

