Vue3.0版本會將數據劫持的方式從Object.defineProperty
切換爲Proxy
,因此找了時間從新回顧了一下屬性描述,並瞭解瞭如下Proxy
vue
給對象的屬性設置屬性描述,接受三個參數bash
/*
* obj:須要定義屬性的對象
* prop:定義描述的屬性名
* descriptor: 屬性描述
*/
Object.defineProperty(obj, prop, descriptor);
複製代碼
用於描述屬性的對象,能夠包含如下值app
屬性在獲取值的時候會調用該方法ui
var obj = {}
Object.defineProperty(obj, 'a', {
get() {
console.log('get a');
return 1;
}
})
console.log(obj.a)
// 優先輸出'get a', 以後輸出:1
複製代碼
屬性設置值的時候會調用該方法spa
var obj = {}
Object.defineProperty(obj, 'a', {
set(value) {
console.log(`set:${value}`);
}
})
obj.a = 1
// 輸出 `set:1`
複製代碼
用於設置對象屬性的初始值,沒法同get
和set
方法同時設置代理
var obj = {}
Object.defineProperty(obj, 'a', {
value: 1
})
console.log(obj.a) // 1
複製代碼
設置屬性是否能夠枚舉,用於for in
枚舉屬性時候是否能夠獲取code
var obj = {}
Object.defineProperty(obj, 'a', {
value: 1,
enumerable: false, // 設置false沒法經過for in獲取
})
console.log(obj.a) // 1
for(let key in obj) {
console.log(`key:${key}`) // 不會執行
}
複製代碼
設置屬性是否能夠再次定義屬性描述orm
var obj = {}
Object.defineProperty(obj, 'a', {
value: 1,
configurable: false, // 設置false沒法再次配置屬性
})
Object.defineProperty(obj, 'a', {
value: 2,
})
// 拋出異常:Uncaught TypeError: Cannot redefine property 'a'
複製代碼
PS:對於已有屬性能夠修改value
和enumerable
和writable
的值(例如:若是obj = {a: 1}
這裏修改屬性a
的這三個值不會報錯)cdn
設置屬性是否能夠賦值,沒法同get
和set
方法同時設置對象
var obj = {}
Object.defineProperty(obj, 'a', {
value: 1,
writable: false, // 設置false,沒法被普通賦值
})
obj.a = 2
console.log(obj.a) // 1
複製代碼
阻止對象擴展新的屬性,不過並不限制對象原型上的屬性擴展
var obj = {a: 1}
Object.preventExtensions(obj)
obj.b = 2 // 嚴格模式下拋出TypeError異常
console.log(obj) // {a: 1}
複製代碼
可使用Object.isExtensible(obj)
來判斷是否已經阻止擴展了
將使得對象禁止擴展屬性,同時禁止現有屬性的configurable
var obj = {a: 1}
Object.seal(obj)
console.log(Object.isExtensible(obj)) // false
Object.defineProperty(obj, 'a', {
value: 2
}) // 拋出異常
複製代碼
至關於Object.preventExtensions
的基礎上,將已有屬性的configurable
都設置爲false
var obj = {a: 1}
Object.preventExtensions(obj)
Object.defineProperty(obj, 'a', {
configurable: false
})
console.log(Object.isSealed(obj)) // true
複製代碼
可使用Object.isSealed(obj)
判斷是否屬性屬於該狀況
在Object.seal()
的基礎上,將屬性的writable
設置爲false
var obj = {a: 1}
Object.freeze(obj)
console.log(Object.isSealed(obj)) // true
obj.a = 2
console.log(obj.a) // 1
複製代碼
至關於
var obj = {a: 1}
Object.seal(obj)
Object.defineProperty(obj, 'a', {
writable: false
})
console.log(Object.isFrozen(obj)) // true
複製代碼
可使用Object.isFrozen(obj)
判斷是否屬性屬於該狀況
同Object.defineProperty
,可一次性批量定義多個對象屬性
Object.defineProperties(obj, {
prop1: {
get() {}
set() {}
...
},
prop2: {
get() {}
set() {}
...
}
})
複製代碼
使用Proxy能夠建立一個對象的代理
使用new Proxy(target, handler)
能夠建立對象target
的proxy
對象,操做proxy
對象的時候,根據設置的handler
,能夠設置對象操做的各時期的具體操做
getPrototypeOf()
:在調用Object.getPrototypeOf()
的時候setPrototypeOf()
:在使用Object.setPrototypeOf()
的時候isExtensible()
:在使用Object.isExtensible()
的時候preventExtensions()
:在使用Object.preventExtensions()
的時候getOwnPropertyDescriptor()
:在使用Object.getOwnPropertyDescriptor()
的時候defineProperty()
:在使用Object.defineProperty()
的時候has()
:在使用in
操做符的時候get()
:在獲取屬性值的是歐set()
:在設置屬性值的時候deleteProperty()
:在delete
刪除屬性的時候ownKeys()
:在Object.getOwnPropertyNames()
和Object.getOwnPropertySymbols()
的時候apply()
:在對象做爲方法調用的時候construct()
:在使用new
操做符的時候以set
舉例說明:
var obj = {}
var proxy = new Proxy(obj, {
set (target, prop, value) {
console.log('set value')
target[prop] = value
}
})
proxy.a = 1 // 'set value'
console.log(obj) // {a: 1}
複製代碼
操做proxy
對象能夠修改對應對象的屬性信息,可是直接操做target
對象,並不會觸發proxy
對象中設置的操做:
var obj = {}
var proxy = new Proxy(obj, {
set (target, prop, value) {
console.log('set value')
target[prop] = value
}
})
obj.a = 1 // 並不會輸出任何信息
console.log(obj) // {a: 1}
複製代碼
建立一個能夠revocable對象,能夠在須要廢棄proxy對象的時候銷燬
var revocable = Proxy.revocable({}, {
set (target, prop, value) {
console.log('set value')
target[prop] = value
}
})
revocable.proxy.a = 1 // 'set value'
revocable.revoke() // 銷燬對象
revocable.proxy.a = 2 // Uncaught TypeError: Cannot perform 'set' on a proxy that has been revoked
複製代碼
從目的來看Proxy
和defineProperty
都是爲了擴展對象的特性,若是要用來實現MVVM,兩種方案均可以完成
從三個方面來講明
defineProperty
主要是用於對象定義屬性,注重的是設置對象中屬性的描述,而Proxy
用於處理對象,注重的是對象的相關操做defineProperty
的時候,是須要直接操做對象自己,來觸發相關屬性設置,而Proxy
則須要操做new
建立的proxy
對象,對原對象操做並不會觸發相關內容defineProperty
只提供了set
,get
方法能夠做爲切入口,而Proxy
提供了更豐富的對象操做切入口總的來講vue3.0使用Proxy
的目的在於對對象劫持的時候,不用遍歷全部屬性,能夠直接使用對象的proxy
對象,同時在對象追加屬性的增長劫持的時候,不用再手動使用$set
添加劫持
固然和Proxy
密切相關的Reflect
,這個就留在下次再說了
本文存在的問題還望各位指正,謝謝