淺談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
-----結束