1. 程式人生 > 其它 >淺談vue2和vue3之間的響應式原理

淺談vue2和vue3之間的響應式原理

既然vue2和vue3都是基於vue的,為什麼底層會一直改變,原本不想學習vue3的,覺得夠用就行,但是有時候在vue2的專案中卻會發現一種難以言語的不便

比如你不可能直接的去修改或者刪除某個物件的屬性或者值,儘管你可以通過set方法去修改,但是為什麼不能修改呢,本質是資料雖然修改了但是頁面還是呈現不出來呢?

~所以,前端搬運工還是要往前繼續走,繼續踩

 

模擬vue2的響應式原理

回顧一下Object.defineProperty()這是啥,我們去MDN走一趟----

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

得到的解釋是 ----

Object.defineProperty() 方法會直接在一個物件上定義一個新屬性,或者修改一個物件的現有屬性,並返回此物件。

語法----

Object.defineProperty(obj, prop, descriptor)

傳值---

configurable
當且僅當該屬性的 configurable 鍵值為 true 時,該屬性的描述符才能夠被改變,同時該屬性也能從對應的物件上被刪除。
預設為 false
enumerable
當且僅當該屬性的 enumerable 鍵值為 true 時,該屬性才會出現在物件的列舉屬性中。
預設為 false

資料描述符還具有以下可選鍵值:

value
該屬性對應的值。可以是任何有效的 JavaScript 值(數值,物件,函式等)。
預設為 undefined
writable
當且僅當該屬性的 writable 鍵值為 true 時,屬性的值,也就是上面的 value,才能被賦值運算子 (en-US)改變。
預設為 false

存取描述符還具有以下可選鍵值:

get
屬性的 getter 函式,如果沒有 getter,則為 undefined。當訪問該屬性時,會呼叫此函式。執行時不傳入任何引數,但是會傳入 this 物件(由於繼承關係,這裡的this並不一定是定義該屬性的物件)。該函式的返回值會被用作屬性的值。
預設為 
undefined
set
屬性的 setter 函式,如果沒有 setter,則為 undefined。當屬性值被修改時,會呼叫此函式。該方法接受一個引數(也就是被賦予的新值),會傳入賦值時的 this 物件。
預設為 undefined

通過下面的案例想想vue2的響應式原理以及資料劫持是如何的,順便再想想vue.js的的設計模式--釋出者-訂閱者,可以去玩一下pubsub.js 這裡只是淺談一下響應式原理

 //初資料
let person = {
name:'張大標',
age:90
}

let p = {}
Object.defineProperty(p,'name',{
configurable:true,
get(){ 
return person.name
},
set(value){ 
person.name = value
}
})
Object.defineProperty(p,'age',{
get(){
return person.age
},
set(value){
person.age = value
}
}) 

 

模擬vue3的響應式原理

 

我們先了解一下Proxy --- 代理

定義---

Proxy 物件用於建立一個物件的代理,從而實現基本操作的攔截和自定義(如屬性查詢、賦值、列舉、函式呼叫等)。

引數---

target
要使用 Proxy 包裝的目標物件(可以是任何型別的物件,包括原生陣列,函式,甚至另一個代理)。
handler
一個通常以函式作為屬性的物件,各屬性中的函式分別定義了在執行各種操作時代理 p 的行為。

那麼p如何去對映person呢?那是不是直接聯想到資料劫持?

const p = new Proxy(person,{
get(target,property){
return Reflect.get(target,property)
},
set(target,property,value){
Reflect.set(target,property,value)
},
deleteProperty(target,property){  //最關鍵的是這裡,捕獲資料的改變做響應式
return Reflect.deleteProperty(target,property)   //   如果這裡不明白,接著看.......--->>>>
}
})

 

再來引入下為什麼要用Reflect --- 對映  

Reflect 是一個內建的物件,它提供攔截 JavaScript 操作的方法。這些方法與proxy handlers (en-US)的方法相同。Reflect不是一個函式物件,因此它是不可構造的。

一個簡單的reflect的例子-----

     讀操作----

 

 

     寫操作---

    

 

     刪除操作---

 

 

 似乎你會覺得操作物件不需要用到reflect,但是reflec正在被ECMA在Object的大量API移植到其身上,如下文件----->

   https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect

 

 -----結束