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
,这个就留在下次再说了
本文存在的问题还望各位指正,谢谢