详解Object.defineProperty,Proxy,Re
Object.defineProperty
Object.defineProperty会在一个对象上添加一个属性,获者修改一个属性,截取的是对象的属性
方法接收三个参数(obj,key,desc)
属性描述符的类型有两种
- 数据属性(Data Properties)描述符(Descriptor)
-
存取属性(Accessor访问器 Properties)描述符(Descriptor)
desc
1.数据属性描述符
//在直接定义一个对象,所有的数据特性都是为true
var obj = {
name: 'jack',
age: 18,
};
//在使用数据描述符时,所有的默认特性都是为false
//configurable和enumerable + value和writable
Object.defineProperty(obj, 'address', {
//属性的值,默认为undefined
value: 'ad',
//是否可以配置进行delete关键字进行删除,
configurable: true,
//可枚举,进行循环遍历时是否可以拿到相应的key
enumerable: true,
//属性是否可以写入值
writable: true,
});
- 存取描述符
var obj = {
name: 'jack',
age: 18,
_address: 'xxx',
};
//configurable和enumerable + get和set方法
//1.在不想私有属性被暴露,可以通过数据存取描述符进行代理
//2.可以收集依赖,
Object.defineProperty(obj, 'address', {
enumerable: true,
configurable: true,
get: function () {
return this._address; //在访问address时代理给_address
},
set: function (value) {
return this._address = value; //在设置新的值时赋值给_address
},
});
obj.address = 'aaa';
console.log(obj.address);
vue2的响应式原理就是应用了存取描述符,在get时将属性在哪个地方使用时收集依赖,当属性被改变时,在set方法自动更新在哪个地方使用的属性值
但是Object.defineProperty设计的初衷,不是为了去监听截止一个对象中所有的属性的,我们在定义某些属性的时候,初衷其实是定义普通的属性,但是后面我们强行将它变成了数据属性描述符,其次,如果我们想监听更加丰富的操作,比如新增属性、删除属性,那么Object.defineProperty是无能为力的,所有js在es6的更新的时候加了一个Proxy类
Proxy
在ES6中,新增了一个Proxy类,这个类从名字就可以看出来,是用于帮助我们创建一个代理的,也就是说,如果我们希望监听一个对象的相关操作,那么我们可以先创建一个代理对象(Proxy对象),之后对该对象的所有操作,都通过代理对象来完成,代理对象可以监听我们想要对原对象进行哪些操作
const obj = {
name:'jack',
age:18
}
const objproxy =new Proxy(obj)
当下次需要操作obj时,可以先操作代理对象
Proxy的set和get捕获器
get函数有三个参数:
- target:目标对象(侦听的对象);
- property:被获取的属性key;
- receiver:调用的代理对象
set函数有四个参数: - target:目标对象(侦听的对象);
- property:将被设置的属性key;
- value:新属性值;
- receiver:调用的代理对象
Proxy所有捕获器
Proxy捕获器Proxy给对象提供了13种捕获器,在进行代理对象的时候基本上都涵盖所有的操作,利用Proxy进行响应式是非常好的选择
Reflect
Reflect也是ES6新增的一个API,它是一个对象,字面的意思是反射
主要作用
- 它主要提供了很多操作JavaScript对象的方法,有点像Object中操作对象的方法
- 比如Reflect.getPrototypeOf(target)类似于 Object.getPrototypeOf()
- 比如Reflect.defineProperty(target, propertyKey, attributes)类似于Object.defineProperty()
和Object是类似的,但是为什么还要新增一个呢,这是因为在早期的ECMA规范中没有考虑到这种对 对象本身 的操作如何设计会更加规范,所以将这些API放到了Object上面,为了规范在es6中新增了Reflect类,可以去看一下Object和Reflect的区别
Reflect的常见方
reflectReflect的使用
一般都是在set中传入数据,然后直接将newValue赋值给val
const objProxy = new Proxy(obj,{
set(targrt,key,newValue){
return target[key] = newValue
}
})
但是这种直接操作是在原对象上直接操作数据的,本来是用了一个对象代理,但是在操作数据的时候还是操作原对象的,为了能够不直接更改原数据,这里可以利用reflect将数据进行一个代理,就像下面的这样使用
image.png