之前学了vue3课程(vue3的响应式原理使用的就是Proxy),课程中老师经常提到proxy、响应式原理等,感觉很难很高深。现在学了,才真正了解。
一、Proxy类(代理)
监听一个对象的相关操作,比如对象添加、删除、修改属性等。通过捕获器监听对象的改变。
在es6直接如果想要监听对象的改变,需要使用Object.defineProperty()进行监听。代码如下:
1.Object.defineProperty()监听对象改变
const obj = {name:'wgy',age:18}
Object.defineProperty(obj,'name',{
get:function(){
console.log('name属性被访问了')
},
set:function(newVal){
console.log('name属性被设置了',newVal)
}
})
console.log(obj.name)
obj.name = 'kobo'
2.Object.defineProperty()的缺点
-
比如新增属性、删除属性,defineProperty监听不到
-
defineProperty的设计初衷是定义普通的属性,不是为了去监听一个对象中的所有属性
3.Proxy监听对象改变
const obj = { name: "wgy", age: 18 };
const objProxy = new Proxy(obj, {
// 获取值时的捕获器 target-obj,key-name
get(target, key, receiver) {
console.log("值被获取了", target, key);
return target[key];
},
// 设置值时的捕获器
set(target, key, newValue, receiver) {
console.log("值被设置了", newValue);
target[key] = newValue;
},
// 监听in的捕获器
has(target, key) {
console.log("对象执行了in操作");
return key in target;
},
// 监听delete的捕获器
deleteProperty(target, key) {
console.log("对象执行了delete操作");
delete target[key];
},
});
console.log(objProxy.name);
objProxy.name = "3333";
console.log(obj);
console.log("name" in objProxy);
delete objProxy.name;
4. 其他捕获器
-
getPrototype()
-
Object.getPrototypeof() 获取对象的原型
-
-
setPrototype()
-
Object.setPrototypeof() 设置对象的原型
-
-
isExtensible()
-
Object.isExtensible() 判断对象是否可以添加属性
-
-
preventExtensions()
-
Object.preventExtensions() 阻止对象添加属性
-
-
getOwnPrototyDescriptor()
-
Object.getOwnPrototyDescriptor() 获取对象的属性描述符
-
-
defineProperty()
-
Object.defineProperty() 给对象添加属性描述符
-
-
ownKeys()
-
Object.getOwnPrototyNames()
-
Object.getOwnPrototySymbols()
-
-
apply() 用于函数对象
-
监听函数调用操作
-
-
construct 用于函数对象
-
监听new 操作符
-
//apply()和construct()捕获器用于函数对象,使用方法
function foo() {
console.log(foo);
}
const fooProxy = new Proxy(foo, {
apply(target, thisAry, argArray) {
console.log("函数被调用了", thisAry, argArray);
target.apply(thisAry, argArray);
},
construct(target, argArray, newTarget) {
console.log("函数使用new");
return new target(...argArray);
},
});
fooProxy();
fooProxy.apply({}, [1, 4, 6]);
new fooProxy();
5.Proxy的receiver参数的使用
修改this指向,是代理有意义。
const obj = {
_name: "www",
get name() {
console.log(this);
return this._name; //this指向obj
},
set name(newVal) {
this._name = newVal;
},
};
const objProxy = new Proxy(obj, {
get(target, key, receiver) {
// receiver是代理对象objProxy
console.log("属性被获取了", key, receiver === objProxy);
return Reflect.get(target, key, receiver);
// 传入receiver,会把this改为代理对象receiver
},
set(target, key, newVal, receiver) {
console.log("属性被设置了");
Reflect.set(target, key, newVal, receiver);
},
});
console.log(objProxy.name); //访问的是obj的get name
objProxy.name = "333333";
二、Reflect对象(映射)
Reflect对象提供了很多操作js对象的方法,比如增删改等。与Object提供的方法类似。
一般与Proxy配合使用。
const obj = { name: "www", age: 22 };
const objProxy = new Proxy(obj, {
get(target, key) {
// return target[key]
return Reflect.get(target, key);
},
set(target, key, newValue) {
// target[key] = newValue;
let res = Reflect.set(target, key, newValue);
console.log(res);//会返回设置结果
},
});
console.log(objProxy);
objProxy.name = "hhh";
1.为什么会需要Reflect
-
早期的ECMA规范中没有考虑到对对象本地操作如何设计会更规范,所以将这些方法API放到了Object上
-
Object作为一个构造函数,这些放到他身上不合适
-
还包含一下类似于in、delete操作符,让js看起来有点奇怪
2.与Object方法的区别
可参考比较 Reflect 和 Object 方法 - JavaScript | MDN
3.Reflect的方法
-
Reflect.apply()
-
对一个函数进行调用操作,同时可以传入一个数组作为调用参数。
-
-
Reflect.construct(target, argumentsList[, newTarget])
-
对构造函数进行new操作
-
-
Reflect.defineProperty(target, propertyKey, attributes)
-
Object.defineProperty()
-
-
Reflect.deleteProperty(target, propertyKey)
-
Object.preventExtensions() 阻止对象添加属性
-
-
Reflect.get(target, propertyKey[, receiver])
-
获取对象的属性
-
-
Reflect.getOwnPropertyDescriptor(target, propertyKey)
-
Object.getOwnPropertyDescriptor()
-
-
Reflect.getPrototypeOf(target)
-
Object.getPrototypeOf()
-
-
Reflect.has(target, propertyKey)
-
Object.isExtensible()
-
-
Reflect.ownKeys(target)
-
Object.keys()
-
-
Reflect.preventExtensions(target)
-
Object.preventExtensions()
-
-
Reflect.set(target, propertyKey, value[, receiver])
-
设置对象属性
-
-
Reflect.setPrototypeOf(target, prototype)
-
设置对象的原型
-
4.Reflect.construct()的使用
const stu = new Student("ww", 32);
console.log(stu);
console.log(stu.__proto__ === Student.prototype);
// 执行Student函数,创建出来的对象是Teacher对象
const tea = Reflect.construct(Student, ["wwww", 22], Teacher);
console.log(tea);
console.log(tea.__proto__ === Teacher.prototype);