关于 proxy 对象的一些疑问?

懂了懂了,最开始对proxy的理解有误,感谢各位指点
user === proxyUser -> false
user.wife === proxyUser.wife -> true


看到一些教程,说proxy只拦截一层,就像vue3的shallowReactive,试了下有两个疑问:

  1. 虽然没打印set拦截,但是目标对象user.wife.name的确变了,为什么?
  2. user和proxyUser指向的地址是同一个吗?? ---- 这个我懂了,user === proxyUser是false
let user = {
    name: "foo", 
    age: 25,
    job: ['a', 'b'],
    wife: {
        name: 'bar',
        age: 24
    }
};  
let proxyUser = new Proxy(user, {
     get(target, prop) {
         console.log('劫持get()', prop)
         return Reflect.get(target, prop)
     },
     set(target, prop, val) {
         console.log('劫持set()', prop, val)
         return Reflect.set(target, prop, val);
     },
     deleteProperty (target, prop) {
         console.log('劫持delete属性', prop)
         return Reflect.deleteProperty(target, prop)
     }
 });  

proxyUser.wife.name = 'bb' // 只打印了:劫持get() wife   没有打印:劫持set()
console.log(user.wife.name)    //    打印:bb  ???? why???
阅读 1.8k
3 个回答

你是把自己绕晕了吗,只拦截一层,那么wife是第二层所以不打印set不是符合预期吗?直接访问user源对象当然就不走拦截器了这有什么疑问?

你代理的是 user 这个对象,而不是 wife 这个对象

proxyUser.wife.name = 'bb'

相当于

const wife = proxyUser.wife // 先获取 user 的 wife,会被劫持
wife.name = 'bb' // 然后再设置 wife 的 name,不会被劫持

想要劫持到 name 的设置,应该代理 wife

let user = {
    name: "foo", 
    age: 25,
    job: ['a', 'b'],
    wife: {
        name: 'bar',
        age: 24
    }
};  
let proxyWife = new Proxy(user.wife, {
     set(target, prop, val) {
         console.log('劫持set()', prop, val)
         return Reflect.set(target, prop, val);
     }
 });  

proxyWife.name = 'bb' // 劫持set() name bb
console.log(user.wife.name)    //    bb

先把第二个问题说了,肯定不是,如果一样的话,凭什么对proxyUser的访问有拦截,对user的访问没有。代理代理,是目标的代理,总不能我代理我自己吧。

说回第一个问题:代理归代理,除非你在set里将赋值操作屏蔽掉或者进行修改,否则set操作还是会引用到被代理的对象的,你这里显然没有对赋值操作进行干扰,只是多了一个日志,赋值操作还是会正常的作用于target。

所谓只拦截一层,因为对target的操作仅限于其自身的属性,user.wife.name实际上是先访问user.wife对应的对象,然后对该对象进行操作,可见目标并不是user。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题