obj.defineProperty
Object.defineProperty()
方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。IE8不兼容。
Object.defineProperty(obj,prop,desc)
# 参数
# obj:要定义属性的对象
# prop:要定义或者修改的属性的名称或者是Symbol
# desc:要定义或修改的属性描述符
属性值:
对象中目前存在的属性描述符有主要的两种形式:数据描述符和存取描述符
数据描述符:是一个具有值得属性,该值是可写的,也是不可写的
存取描述符:是由get和set函数所描述的属性
这两种描述符都是对象,他们共享
注意:当定义了value或writeable,一定不能有get或set,当定义get或set是,不能出现writeable属性等,否则就会报错
window.PI = 3.14
let _PI = window.PI
// 实现一个常量 第一个参数是定义哪个对象,第二个是定义的什么属性,第三个就是定义options
Object.defineProperty(window,"PI",{
// writable:true, // 设置属性是否可以修改
// value:3.1415926, // 设置属性的值
// configurable:false, // 设置属性是否可以删除
// enumerable:false, // 设置属性是否可以遍历
get() {
// 是属性被访问时,触发的方法
console.log(_PI)
return _PI
},
// 在设置属性或者修改属性时,进行触发set
set(value) {
throw new Error("PI不可以修改")
console.log(value)
_PI = value
}
})
默认值:
configurable:当且仅当该属性的configurable键值为true时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除,默认情况下为false
enumerable:当且仅当该属性的enumerable键值为true时,该属性才会出现在对象的枚举属性中,默认为false
数据描述符具有以下可选键值:
value:该属性对应的值,可以是任何有效的javascript值(数值,对象,函数等),默认为undefined
writeable:当且仅当该属性的writeable简直为true时,属性的值,也就是上边的value值才可以被赋值运算符修改,默认时false
存取描述符还具有以下的可选键值:
get:属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。默认为 undefined
set:属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。默认为 undefined。
Object.defineProperties
Object.defineProperties本质上定义了obj 对象上props的可枚举属性相对应的所有属性。
var obj = {};
Object.defineProperties(obj, {
'property1': {
value: true,
writable: true
},
'property2': {
value: 'Hello',
writable: false
}
// etc. etc.
});
Proxy
Proxy 对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)。IE不兼容。
const p = new Proxy(target, handler)
参数
target: 要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
handler: 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。
返回值
一个Proxy代理的对象,操作这个对象会触发handler对应操作。改变原始对象不会触发。
handler 对象的方法:handler 对象是一个容纳一批特定属性的占位符对象。它包含有 Proxy 的各个捕获器(trap)。
所有的捕捉器是可选的。如果没有定义某个捕捉器,那么就会保留源对象的默认行为。
handler.getPrototypeOf()
handler.setPrototypeOf()
handler.isExtensible()
handler.preventExtensions()
handler.getOwnPropertyDescriptor()
handler.defineProperty()
handler.has()//in 操作符的捕捉器。
handler.get(target, property)
handler.set(target, property, value)
handler.deleteProperty()//delete 操作符的捕捉器。
handler.ownKeys()
handler.apply()
handler.construct()//new 操作符的捕捉器。
Proxy对象和原始对象
let target = {};
let p = new Proxy(target, {});
p.a = 37; // 操作转发到目标
console.log(target.a); // 37. 操作已经被正确地转发
target.a=4;
console.log(p.a)//4
console.log(target==p)//false
总结
1. Proxy使用上比Object.defineProperty方便的多。
2. Proxy代理整个对象,Object.defineProperty只代理对象上的某个属性。
3. vue中,Proxy在调用时递归,Object.defineProperty在一开始就全部递归,Proxy性能优于Object.defineProperty。
4. 对象上定义新属性时,Proxy可以监听到,Object.defineProperty监听不到。
5. 数组新增删除修改时,Proxy可以监听到,Object.defineProperty监听不到。
6. Proxy不兼容IE,Object.defineProperty不兼容IE8及以下。