// 目标对象
const user = {
name: '小小',
age: 20,
wife: {
name: '小明',
age: 19
}
}
// 把目标对象变成代理对象
const proxyUser = new Proxy(user, {
// 获取
get(target, prop) {
console.log('get方法调用了')
console.log(target)
return Reflect.get(target, prop)
},
// 新增、修改
set(target, prop, val) {
console.log('set方法调用了')
return Reflect.set(target, prop, val)
},
// 删除
deleteProperty(target, prop) {
console.log('delete方法调用了')
return Reflect.deleteProperty(target, prop)
}
})
// 触发get
console.log(proxyUser.name)
// 触发set
proxyUser.age += 1;
proxyUser.gender = 'man'
// 触发delete
delete proxyUser.name
// 更新目标对象中的某个属性对象中的属性值
proxyUser.wife.name = "天天天三百"
console.log(user)
Reflect 是一个window 内置的一个全局对象,它提供拦截 JavaScript 操作的方法。
与大多数全局对象不同,Reflect并非一个构造函数,所以不能通过new 运算符对其进行调用,或者将Reflect对象作为一个函数来调用。Reflect的所有属性和方法都是静态的(就像Math对象)
Reflect.get(target, propertyKey[, receiver])
---- 从一个对象中取属性值返回值:属性的值
// Object
var obj = { x: 1, y: 2 };
Reflect.get(obj, "x"); // 1
// Array
Reflect.get(["zero", "one"], 1); // "one"
// Proxy with a get handler
var x = {p: 1};
var obj = new Proxy(x, {
get(t, k, r) { return k + "bar"; }
});
Reflect.get(obj, "foo"); // "foobar"
Reflect.set(target, propertyKey, value[, receiver])
---- 为对象设置或修改属性值返回值 : 返回一个 Boolean 值,表明是否成功设置属性。
// Object
var obj = {};
Reflect.set(obj, "prop", "value"); // true
obj.prop; // "value"
// Array
var arr = ["duck", "duck", "duck"];
Reflect.set(arr, 2, "goose"); // true
arr[2]; // "goose"
Reflect.set(arr, "length", 1); // true
arr; // ["duck"];
Reflect.deleteProperty(target, propertyKey)
---- 用于删除属性返回值 : 返回一个 Boolean 值,表明该属性是否被成功删除.
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]
arr[3] // undefined
// 如果属性不存在,返回 true
Reflect.deleteProperty({}, "foo"); // true
// 如果属性不可配置,返回 false
Reflect.deleteProperty(Object.freeze({foo: 1}), "foo"); // false
Reflect.has(target, propertyKey)
----- 需要检查目标对象是否存在此属性。返回值 : 返回一个 Boolean 值,表示是否存在此属性
Reflect.has({x: 0}, "x"); // true
Reflect.has({x: 0}, "y"); // false
// 如果该属性存在于原型链中,返回 true
Reflect.has({x: 0}, "toString");
Reflect.apply(target,thisArgument,argumentsList)
Reflect.apply(Math.floor, undefined, [1.75]); // 1
Reflect.apply("".charAt, "ponies", [3]); // "i"
注意:Reflect 不支持 ie浏览器,所以Vue3不支持ie
在使用Object.defineProperty的时候,我们遇到的问题有:
1.一次只能对一个属性进行监听,需要遍历来对所有属性监听。这个我们在上面已经解决了。
2. 在遇到一个对象的属性还是一个对象的情况下,需要递归监听。
3. 对于对象的新增属性,需要手动监听
4. 对于数组通过push、unshift方法增加的元素,也无法监听
这些问题在Proxy中都轻松得到了解决。
举个例子
const target = {
foo: 24,
get bar () {
return this.foo
}
}
const observed = reactive(target)
此时,如果不用 Reflect.get,而是 target[key],那么这里上下文中的 this 就指向target,而不是 observed
。
那么,之后你通过this去访问数据时,你访问的就是代理之前的对象,而不是代理之后的Proxy对象。这样用户对对象的操作你就无法监听到了,就无法触发回调,进行其它操作了;
而Reflect的get、set方法中的第三个参数receiver,就是修改this指向的;所以,我们要通过 Reflect 中的get、set方法将上下文中的 this 指向代理对象。这样的话,之后访问数据时,访问的就是Proxy代理后的对象了,同时也就会触发Proxy对象中的get、set方法了,从而也就能触发回调,进行其它操作了;