公司的新項目決定使用Vue.js來作,當我打印出Vue實例下的data對象裏的屬性時,發現了一個有趣的事情:vue
它的每一個屬性都有兩個相對應的get和set方法,我覺的這是畫蛇添足的,因而去網上查了查Vue雙向綁定的實現原理,才發現它和Angular.js雙向綁定的實現原理徹底不一樣,Angular是用的數據髒檢測,當Model發生變化,會檢測全部視圖是否綁定了相關數據,再更改視圖。而Vue使用的發佈訂閱模式,是點對點的綁定數據。緩存
Vue的數據綁定只有兩個步驟,compile=>link。框架
我一直在想,vue是經過什麼去監聽用戶對Model的修改,直到我發現Vue的data裏,每一個屬性都有set和get屬性,我才明白過來。函數
在平時,咱們建立一個對象,並修改它的屬性,是這樣的:this
var obj = { val:99 } obj.val = 100; console.log(obj.val)//100
沒有任何問題,可是若是要你去監測,當我修改了這個對象的屬性時,要去作一些事,你會怎麼作?spa
這就要用到getter和setter了。prototype
假設我如今要給一個碼農對象添加一個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)
輸出:code
你會發現這個對象和最上面的Vue中的data對象,打印出來的效果是同樣的,都擁有get和set屬性。對象
咱們來一步步分析下上面的代碼,頗有趣。
咱們先建立一個對象字面量:
var Coder = function() {...}
再把this緩存一下:
var that = this;
接下來是最重要的,咱們return了一個對象回去:
{
get name(){...},
set name(val){...}
}
顧名思義,get爲取值,set爲賦值,正常狀況下,咱們取值和賦值是用obj.prop的方式,可是這樣作有一個問題,我如何知道對象的值改變了?因此就輪到set登場了。
你能夠把get和set理解爲function,固然,只是能夠這麼理解,這是徹底不同的兩個東西。
接下來建立一個碼農的實例,isMe;此時,isMe是沒有name屬性的,當咱們調用isMe.name時,咱們會進入到get name(){...}中,先判斷isMe是否有name屬性,答案是否認的,那麼就添加一個name屬性,並給它賦值:"你尚未取名";若是有name屬性,那就返回name屬性。
看到這裏你必定知道get怎麼使用了,對,你能夠把get當作一個取值的函數,函數的返回值就是它拿到的值。
我感受比較重要的是set屬性,當我給實例賦值:
isMe.name="周神"
此時,會進入set name(val){...};形參val就是我賦給name屬性的值,在這個函數裏,我就能夠作不少事了,好比雙向綁定!由於這個值的每次改變都必須通過set,其餘方式是改變不了它的,至關於一個萬能的監聽器。
還有另外一種方法能夠實現這個功能。
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)
效果是同樣的,建議使用下面這種方式,由於是在原型上書寫,因此能夠繼承和重用,最近想寫點小框架,才發現知識不夠用,你們一塊兒加油吧!