若是你對Vue發佈訂閱的響應式實現有必定的瞭解,那麼你必定知道defineProperty。react
Object.defineProperty(obj, prop, descriptor)
es6
Vue2.x中的響應式實現正是基於defineProperty中的descriptor,經過屬性的getter、setter監聽來實現的。typescript
同時你應該知道的是,咱們在Vue中使用下標的方式直接修改屬性的值或者添加一個預先不存在的對象屬性是沒法作到setter監聽的,這是defineProperty的侷限性。數組
而咱們在Vue中使用的push、pop、shift、unshift、splice等一系列修改原數組的方法,其實不是原生的數組方法,都是被Vue修改過的,其中加入了響應代碼。性能
有消息稱Vue3.0的響應式將會使用Proxy來實現,這一舉動無疑優化了Vue的響應能力,可是也決定了Vue將會完全拋棄IE陣營,咱們是否應該默(qing)哀(zhu) 一分鐘。測試
defineProperty的侷限性的最大緣由是它只能針對單例屬性作監聽,Vue2.x中對data中的屬性作了遍歷 + 遞歸,爲每一個屬性設置了getter、setter。優化
這也就是爲何Vue只能對data中預約義過的屬性作出響應的緣由。ui
var val = 1
var obj = Object.defineProperty({}, 'sum', {
enumerable: true,
configurable: true,
get() {
return val
},
set(newValue) {
val += newValue
}
})
複製代碼
咱們也能夠這樣寫:spa
var val = 1
var obj = {
get ['sum']() {
return val
},
set ['sum'](newValue) {
val += newValue
}
}
複製代碼
這段代碼和上面代碼結果是同樣的。3d
這裏的'sum'
就是被監聽的屬性名,也就是咱們須要監聽的「一個」屬性。
正是由於使用defineProperty每次只能綁定一個屬性監聽,因此Vue在遍歷 + 遞歸時要有更大的性能消耗和更多的代碼。
Vue3.0終於要使用Proxy,就像上文說的同樣,首先應該對IE表示沉(xi)痛(wen)哀(le)悼(jian)。
Proxy 能夠理解成,在目標對象以前架設一層「攔截」,外界對該對象的訪問,都必須先經過這層攔截,所以提供了一種機制,能夠對外界的訪問進行過濾和改寫。
也就是說,Proxy的監聽是針對一個對象的,那麼對這個對象的全部操做會進入監聽操做,這就徹底能夠代理全部屬性了。
更多Proxy用法能夠看 阮一峯大神的ES6入門-Proxy,本文只講解getter、setter實現。
var data = {
sum: 0
}
var proxy = new Proxy(data, {
get(target, property) {
return target[property]
},
set(target, property, value) {
target[property] += value
}
})
複製代碼
當data爲數組時:
get接收三個參數: get(target, propKey, receiver)
target
是被監聽對象,在示例代碼中表示的是data propKey
是屬性名,即當前須要獲取的屬性名 receiver
是監聽對象,即Proxy實例,在示例代碼中表示的是proxy
set接收四個參數: get(target, propKey, value, receiver)
target
、 propKey
、receiver
三個參數和get中同樣 value
表示被修改的值,即測試代碼中的1
很明顯的是,咱們使用Proxy時並不須要關心某一個具體的屬性,而且Proxy實例上的修改不會影響到被監聽對象target
中的值(前提是你不主動修改target
)。
讓咱們看看如下代碼:
var data = {
a: { b: 0 }
}
var proxy = new Proxy(data, {
get(target, property) {
console.log(`path: ${property}`)
return target[property]
},
set(target, property, value) {
console.log(`path: ${property}`)
target[property] += value
}
})
複製代碼
打印結果:
很明顯的是,proxy代理getter、setter只會關注淺層數據,而不會返回深層路徑。
若是path在這裏可以返回a.b
那麼將會帶來一個很好的收益,不過既然Proxy規範沒有實現那麼咱們也是機關用盡。
並且從理解上來講修改proxy.a.b
返回的修改對象名是a
貌似也是正確的,如今咱們須要作的是記住這一結論就好。
Proxy和defineProperty中getter、setter的用法就說到這裏。
能夠預見的是,Vue3.0中使用Proxy代理將會帶來很大的性能提高和更優的代碼。
可是就像react中約定的同樣,對於引用類型值的響應式的支持可能會變得比之前更不友好(須要開發者實現淺拷貝賦值)。
不過若是尤大依舊選擇使用遞歸的方式來解決對象類型數據的響應式,我我的看來是有些得不償失的。
從我本身的意願來看,我更但願是藉助於immutable,而不是走遞歸遍歷的老路。
相信尤大必定會有本身的考量,最終的結果確定是令大部分人滿意的方案。
同時Vue3支持typescript的方向更是令我激動不已,做爲尤大的粉絲,咱們好好期待就是了。