走进 Reflect,Proxy,系统掌握 Vue3 底层响应式 API
Reflect反射
- 囊括了 JS 内部一些专有方法,例如
Object.keys
、Object.getownPropertyName
、Objecct.delete
等
const obj = {
name: "云牧"
};
// 直接操作
obj.name;
// Reflect
Reflect.get(obj, "name");
// Object 静态方法操作
Object.defineProperty(obj, "age", {
value: 100
});
// Reflect
Reflect.defineProperty(obj, "age", {
value: 100
});
console.log(obj.age); // 100
Proxy对象
- 创建一个对象的代理,从而实现基本操作的拦截和自定义
const p = new Proxy(target, handler);
// target 可以是对象、数组、函数、代理
// handler 是一个对象,内部每个方法定义了执行各种操作时代理 p 的行为
const obj = {};
const proxyObj = new Proxy(obj, {
get(target, property, receiver) {
console.log("get:", target, property, receiver);
// { name: '云牧' }, name, { name: '云牧' }
console.log("get:", target === obj, receiver === proxyObj);
// get: true, true
// 相当于 target[property]
return Reflect.get(target, property);
// 相当于 receiver[property]
return Reflect.get(target, property, receiver);
},
set(target, property, value, receiver) {
console.log("set:", target, property, value, receiver);
// set: {}, name, 云牧, {}
console.log("set:", target === obj, receiver === proxyObj);
// set: true, true
return Reflect.set(target, property, value, receiver);
}
});
proxyObj.name = "云牧";
console.log(proxyObj, obj);
// { name: '云牧' }, { name: '云牧' }
receiver 不是代理对象的情况
情况一:
- 某个对象的原型是一个代理对象
- 设置对象某个属性,本身不存在,但是原型(代理对象)有
- 触发代理对象
set
捕获器,此时receiver === 某个对象
const proto = {
proto_name: "云牧"
};
let testObj;
const proxyProto = new Proxy(proto, {
set(target, property, value, receiver) {
console.log(receiver === proxyProto); // false
// 当设置 proto_name 时为 true
console.log(testObj === receiver);
return Reflect.set(target, property, value, receiver);
}
});
function TestObject(message) {
this.message = message;
}
TestObject.prototype = proxyProto;
testObj = new TestObject("hello");
testObj.message = "world";
testObj.proto_name = "黛玉";
情况二:
- 某个对象原型是代理对象
- 此对象和原型都有相同属性如 name
- 此对象访问原型(代理对象)的 getter 方法,此方法访问 this.name
const proto = {
name: "proto_name",
get nameValue() {
return this.name;
}
};
const proxyObj = new Proxy(proto, {
get(target, property, receiver) {
return Reflect.get(target, property, receiver);
}
});
const obj = {
name: "obj_name"
};
// 设置原型
Object.setPrototypeOf(obj, proxyObj);
// 此时 receiver === proxyObj
console.log("proxyObj.nameValue:", proxyObj.nameValue); // proto_name
// 此时触发原型上的捕获器 receiver === obj
console.log("obj.nameValue:", obj.nameValue); // obj_name
apply 函数调用捕获器
拦截范围:
proxy(..args)
Function.prototype.apply()
Reflect.apply()
Function.prototype.call()
function sum(n1, n2) {
return n1 + n2;
}
const proxySum = new Proxy(sum, {
// 目标对象, 上下文, 参数数组
apply(target, thisArg, argumentsList) {
console.log(target, thisArg, argumentsList);
return Reflect.apply(target, thisArg, argumentsList);
}
});
proxySum(1, 2, 3); // [Function: sum], undefined, [ 1, 2, 3 ]
proxySum.call(null, 1, 2, 3); // [Function: sum], null, [ 1, 2, 3 ]
proxySum.apply(null, [1, 2, 3]); // [Function: sum], null, [ 1, 2, 3 ]
Reflect.apply(proxySum, null, [1, 2, 3]); // [Function: sum], null, [ 1, 2, 3 ]
getPrototypeof 捕获器
拦截范围:
__proto__
instanceof
Object.getPrototypeOf
Reflect.getPrototypeOf
Object.prototype.isPrototypeOf
const obj = {
name: "云牧"
};
const proxyObj = new Proxy(obj, {
getPrototypeOf(target) {
console.log("target:", target); // target: { name: '云牧' }
return Reflect.getPrototypeOf(target);
}
});
proxyObj.__proto__;
console.log(proxyObj instanceof Object); // true
Object.getPrototypeOf(proxyObj);
Reflect.getPrototypeOf(proxyObj);
Object.prototype.isPrototypeOf(proxyObj);
setPrototypeof 捕获器
拦截范围:
Object.setPrototypeOf
Reflect.setPrototypeOf
const obj = {
name: "云牧"
};
const newProto = {
name: "黛玉"
};
const proxyObj = new Proxy(obj, {
setPrototypeOf(target, newProto) {
console.log(target, newProto); // { name: '云牧' }, { name: '黛玉' }
return Reflect.setPrototypeOf(target, newProto);
}
});
Object.setPrototypeOf(proxyObj, newProto);
Reflect.setPrototypeOf(proxyObj, newProto);
construct 捕获器
- 拦截 new 操作
class Person {}
const ProxyPerson = new Proxy(Person, {
construct(target, argumentsList, newTarget) {
console.log(target, argumentsList, newTarget);
// [class Person], [ '云牧', '黛玉' ], ProxyPerson
return Reflect.construct(target, argumentsList, newTarget);
}
});
new ProxyPerson("云牧", "黛玉");
其他捕获器
const obj = {
name: "云牧"
};
const proxyObj = new Proxy(obj, {
// 拦截修改属性描述符信息,
// Object.defineProperty()
// Reflect.defineProperty(),
// proxy.property='value'
defineProperty(target, prop, descriptor) {
return Reflect.defineProperty(target, prop, descriptor);
},
// 拦截 delete 操作
// delete proxy[property] 和 delete proxy.property
// Reflect.deleteProperty()
deleteProperty(target, prop) {
return Reflect.defineProperty(target, prop);
},
// 拦截获取属性描述符
// Object.getOwnPropertyDescriptor()
// Reflect.getOwnPropertyDescriptor()
getOwnPropertyDescriptor(target, prop) {
return Reflect.getOwnPropertyDescriptor(target, prop);
},
// 拦截 in
// property in proxy
// foo in Object.create(proxy)
// with(proxy) { (property); }
// Reflect.has()
has(target, prop) {
return Reflect.has(target, prop);
},
// 拦截让对象不可被扩展
// Object.preventExtensions()
// Reflect.preventExtensions()
preventExtensions(target) {
return Reflect.preventExtensions(target);
},
// 拦截查询对象不可被扩展
// Object.isExtensible()
// Reflect.isExtensible()
isExtensible(target) {
return Reflect.isExtensible(target);
},
// 拦截获取对象属性
// Object.getOwnPropertyNames()
// Object.getOwnPropertySymbols()
// Object.keys()
// Reflect.ownKeys()
ownKeys(target) {
return Reflect.ownKeys(target);
}
});
可取消的代理
- 语法:
Proxy.revocable(target, handler)
- 返回值:
{"proxy": proxy, "revoke": revoke}
-
proxy
:等同于通过new Proxy(target, handler)
创建的代理对象revoke
:取消代理对象的行为
const revocableProxy = Proxy.revocable(
{
name: "云牧"
},
{
get(target, property, receiver) {
console.log("get");
return Reflect.get(target, property, receiver);
}
}
);
const proxyObj = revocableProxy.proxy;
console.log(proxyObj.name); // 会触发 get 捕获器
// 取消代理
revocableProxy.revoke();
// 后续的增删改查对象操作全会报错:TypeError: Cannot perform 'set' on a proxy that has been revoked
// console.log(proxyObj.name);
注意事项
- 捕获器函数里
this
指向new Proxy
的第二个参数对象 new Proxy
生成的代理对象的数据类型和被代理的对象数据一致
const obj = {};
const handler = {
get() {
console.log(this === handler); // true
},
set() {
console.log(this === handler); // true
}
};
const proxyObj = new Proxy(obj, handler);
proxyObj.name = "云牧";
proxyObj.name;
console.log(typeof proxyObj); // object
function sum(n1, n2) {
return n1 + n2;
}
const proxySum = new Proxy(sum, { apply() {} });
console.log(typeof proxySum); // function
转载自:https://juejin.cn/post/7202586763595907128