終於到了講解咱們 Vue 的響應式原理,前面咱們已經講解了 Map
,WeakMap
,Set
,WeakSet
,Proxy
,Reflect
這幾個知識點。那麼接下來思考下到底什麼是響應式,就好比咱們作一個公司的官網,而後要求必須兼容手機端,ipad 端,電腦端,內容屏幕大小變化而變化,這些就須要依賴 JavaScript,CSS, HTML 去處理了。ide
那麼假如咱們像在 Excel 表格中,兩個數字相加,若是一個數字變化了,兩個數字的和確定得變化吧,Excel 表格作到了,可定裏面是作了很大的處理了,那若是使用 JavaScript 來作,咱們該如何作呢?函數
let var1 = 2
let var2 = 3
let sum = var1 + var2
// 當 var1 變化時,
// 該如何通知 sum
若是咱們更新第一個值,sum 不會被修改。this
那麼咱們如何用 JavaScript 實現這一點呢?url
在 Vue 中,在將一個對象數據傳遞給一個組件的時候,Vue 已經給我這些數據設置了 setter
,getter
屬性,一旦數據發生變化,就會獲得響應,這其中就是 Proxy
,Reflect
的很大的功勞。spa
經過前面的知識,咱們知道 Proxy 是一個包含另外一個對象或函數並容許你對其進行攔截的對象。3d
let obj = {
var1: 2,
var2: 3,
sum: 0,
}
let handlerObj = {
get(target, prop) {
if(prop == 'sum') {
target['sum'] = target['var1'] + target['var2']
return target['sum']
}
return target[prop]
},
set(target, prop, newVal) {
target[prop] = newVal
}
}
let p = new Proxy(obj, handlerObj)
console.log(p.sum)
此外,Proxy 還提供了另外一個特性。咱們沒必要像這樣返回值:target[prop]
,而是能夠進一步使用一個名爲 Reflect
的方法,它容許咱們正確地執行 this
綁定,就像這樣:
code
let obj = {
var1: 2,
var2: 3,
sum: 0,
}
let handlerObj = {
get(target, prop) {
if(prop == 'sum') {
target['sum'] = target['var1'] + target['var2']
}
return Reflect.get(...arguments)
},
set(target, prop, newVal) {
target[prop] = newVal
}
}
let p = new Proxy(obj, handlerObj)
console.log(p.sum)
上面咱們已經檢測到了哪些數據發生了變化,因此接下來咱們須要用一個咱們還沒實現的 track
追蹤方法來進行修改:
orm
let obj = {
var1: 2,
var2: 3,
sum: 0,
}
let track = (target, prop) => {
if(prop == 'sum') {
target['sum'] = target['var1'] + target['var2']
}
}
let handlerObj = {
get(target, prop) {
track(target, prop)
return target[prop]
},
set(target, prop, newVal) {
target[prop] = newVal
}
}
let p = new Proxy(obj, handlerObj)
console.log(p.sum)
最後,當某些內容發生改變時咱們會設置新的值。爲此,咱們將經過觸發這些更改來設置新 Proxy 的更改:
對象
let obj = {
var1: 2,
var2: 3,
sum: 0,
}
let track = (target, prop) => {
if(prop == 'sum') {
target['sum'] = target['var1'] + target['var2']
}
}
let trigger = (target, prop, newVal) => {
target[prop] = newVal
}
let handlerObj = {
get(target, prop) {
track(target, prop)
return target[prop]
},
set(target, prop, newVal) {
trigger(target, prop, newVal)
return Reflect.set(...arguments)
}
}
let p = new Proxy(obj, handlerObj)
console.log(p.sum)
effect
trigger