背景
群友在群里提出了一道题目
add[1][2][3] + 4 = 10
add[10][20] + 70 = 100
处理这道题用到了 Proxy,我知道 vue的响应式原理就是从vue2的Object.defineProperty转变为了Proxy,但是一直没有深入了解过
基础知识
什么是 Proxy
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
基本语法
// 语法
//const p = new Proxy(target, handler)
// 代理目标
const target = {}
// 代理对象
const proxyHandler = {}
// 创建一个Proxy
const proxy = new Proxy(target, proxyHandler)
这就是基本的代理创建。
属性查找(get 拦截器)
// 代理目标
const target = { a: 1, b: 2, c: 3, d: 4, e: 5 };
// 代理对象
const proxyHandler = {
//++++++++++++++++++++++++++ start
get() {
return 100; // 这里无论如何访问,返回都是100
},
// ++++++++++++++++++++++++++ edd
};
// 创建一个Proxy
const proxy = new Proxy(target, proxyHandler);
console.log(proxy.a); // 100
console.log(proxy.notExit) // 100
标记的这一块就是我们代理的拦截器,他会拦截所有通过 proxy这个代理对象的访问操作
get(target,property,recevtive) 属性查找(get 拦截器)
- target 没错这个就是我们
初始创建的那个代理目标 - property 就是我们访问的属性,比如
proxy.a,那proerty就是a;proxy.notExit那proerty就是notExit - recevtive 这个就是代理本身,实际就是
recevtive === proxy,但是我不知道这个应用场景在哪里?
// 代理目标
const target = { a: 1, b: 2 };
// 代理对象
const proxyHandler = {
get(target, property, recetive) {
// ++++++++++++++++++++++++++++++ start
if (property in target) {
return target[property];
} else {
return `Sorry, ${property} is not exist`;
}
// ++++++++++++++++++++++++++++++ end
},
};
// 创建一个Proxy
const proxy = new Proxy(target, proxyHandler);
console.log(proxy.a); // 输出: 1
console.log(proxy.notExit); // 输出: Sorry, notExit is not exist
属性赋值(set 拦截器)
set(target,property,value,recetive)
- target、property、recetive同
get拦截器一样 - value : 这个
value就是你设置的proxy.a=100,value就是100
// 代理目标
const target = { a: 1, b: 2 };
// 代理对象
const proxyHandler = {
set(target, property, value, recetive) {
// ++++++++++++++++++++++++++++++ start
console.log(`target[${property}]: ${target[property]} ====> ${value}`);
target[property] = value;
return true; // 返回true表示赋值成功
// ++++++++++++++++++++++++++++++ end
},
};
// 创建一个Proxy
const proxy = new Proxy(target, proxyHandler);
//设置值
proxy.a = 100; // target[a]: 1 ====> 100
属性删除(deleteProperty 拦截器)
deleteProperty(target,property)
- target、property同
get拦截器一样
// 代理目标
const target = { a: 1, b: 2 };
// 代理对象
const proxyHandler = {
deleteProperty(target, property) {
// ++++++++++++++++++++++++++++++ start
console.log(`target[${property}]: ${target[property]}`);
delete target[property];
// ++++++++++++++++++++++++++++++ end
},
};
// 创建一个Proxy
const proxy = new Proxy(target, proxyHandler);
delete proxy.a; // target[a]: 1
delete proxy.notExit; // target[notExit]: undefined
console.log(proxy); // { b: 2 }
枚举(ownKeys 拦截器)
ownKeys(target)
- target同
get拦截器一样
// 代理目标
const target = { a: 1, b: 2 };
// 代理对象
const proxyHandler = {
ownKeys(target) {
// ++++++++++++++++++++++++++++++ start
return ["a"];
// ++++++++++++++++++++++++++++++ end
},
};
// 创建一个Proxy
const proxy = new Proxy(target, proxyHandler);
// 未处理的情况下应该返回 ['a','b']
console.log(Object.keys(proxy)); // 返回值:['a']
函数调用(apply 拦截器)
apply(target, isthis, argumentsList)
- target 这个同上面
get拦截器一样 - isthis 这是函数调用时的
this值,即调用目标函数时this的绑定对象
// 代理目标 如果这是一个箭头函数 isthis 是什么样的呢?
const target = function () {
return this.value;
};
// 代理对象
const proxyHandler = {
apply(target, isthis, argumentsList) {
console.log("target => ", target); // 这是target函数
console.log("isthis:", isthis); // 这个是我们指向的对象 {value: 42}
console.log("argumentsList => ", argumentsList); // 这是参数列表,没有就是 [] *** 注意这里是function函数,如果是箭头函数会是什么?***
return target.apply(isthis, argumentsList);
},
};
// 创建一个Proxy
const proxy = new Proxy(target, proxyHandler);
const content = { value: 42 };
console.log(proxy.apply(content)); // 42
- argumentsList 这是调用目标函数时传递的参数列表,形式为数组
// 代理目标!!!! 这里是一个 function
const target = function (x, y) {
return x + y;
};
// 代理对象
const proxyHandler = {
apply(target, isthis, argumentsList) {
console.log("target => ", target); // target函数
console.log("isthis:", isthis); // undefined
console.log("argumentsList => ", argumentsList); // [1,2]
return target(argumentsList) * 2;
},
};
// 创建一个Proxy
const proxy = new Proxy(target, proxyHandler);
console.log(proxy(1, 2)); // 6
拦截属性定义(defineProperty 拦截器)
defineProperty(target, property, descriptor)
- target、property 同
get拦截器一样 - descriptor 这是包含属性描述符的对象,用于定义或修改属性的特性
const target = {};
// 代理对象
const proxyHandler = {
defineProperty(target, property, descriptor) {
console.log("target => ", target); // {}
console.log("property => ", property); // a
console.log("descriptor => ", descriptor); // { value: 10, writable: true }
return Object.defineProperty(target, property, descriptor);;
},
};
// 创建一个Proxy
const proxy = new Proxy(target, proxyHandler);
Object.defineProperty(proxy, "a", { value: 10, writable: true });
console.log(proxy.a); // 10
新的问题
- Proxy 和 defineProperty 区别是啥?
- vue2 => vue3为什么把defineProperty 转为使用 Proxy