上一篇文章,我们说了 Vue3 用 Proxy 实现响应式的好处,那么面试的时候可能会进一步深挖,会让候选人手写一个响应式。
手写响应式之前,我们现需要先了解一下 Reflect 的作用,这里总结为 3 点
- 1.和 Proxy 一样,也是一个内置对象,方法与 proxy handler 的方法相同
- 2.会替换掉 Object 上的工具函数
示例
const duck = {
name: 'Maurice',
color: 'white',
greeting: function () {
console.log(`Quaaaack! My name is ${this.name}`);
},
};
// 检测一个对象是否存在特定属性
Reflect.has(duck, 'color');
// true
Reflect.has(duck, 'haircut');
// false
// 返回这个对象自身的属性
Reflect.ownKeys(duck);
// [ "name", "color", "greeting" ]
// 为这个对象添加一个新的属性;
Reflect.set(duck, 'eyes', 'black');
// returns "true" if successful
// 删除属性
var obj = { x: 1, y: 2 };
Reflect.deleteProperty(obj, 'x'); // true
obj; // { y: 2 }
var arr = [1, 2, 3, 4, 5];
Reflect.deleteProperty(arr, '3'); // true
arr; // [1, 2, 3, , 5]
// 如果属性不存在,返回 true
Reflect.deleteProperty({}, 'foo'); // true
// 如果属性不可配置,返回 false
Reflect.deleteProperty(Object.freeze({ foo: 1 }), 'foo'); // false
了解完之后,那么下直接贴一下代码
// 创建响应式
function reactive(target = {}) {
// 不是对象或数组,则返回
if (typeof target !== 'object' || target == null) {
return target;
}
// 代理配置
const proxyConf = {
get(target, key, receiver) {
// 只处理本身(非原型的)属性
const ownKeys = Reflect.ownKeys(target);
const result = Reflect.get(target, key, receiver);
// 深度监听
return reactive(result);
},
set(target, key, val, receiver) {
// 重复的数据,不做处理
if (val === target[key]) return true;
const ownKeys = Reflect.ownKeys(target);
const result = Reflect.set(target, key, val, receiver);
return result;
},
deleteProperty(target, key) {
const result = Reflect.deleteProperty(target, key);
console.log('delete property', key);
return result; // 是否删除成功
},
};
// 生成代理对象
const observed = new Proxy(target, proxyConf);
return observed;
}
// 测试数据
const data = {
name: 'tailiang',
age: 20,
info: {
province: 'beijing',
city: 'haidian',
a: {
b: {
c: {
d: {
e: 370,
},
},
},
},
},
};
const proxyData = reactive(data);