Proxy比Object.defineProperty到底好在哪?
本文最后更新于 2024-10-29,文章已经超过3个月未更新,无法保证其有效性,各位大佬请自由斟酌。
大家都知道,从 Vue 3 开始,双向绑定机制从 Object.defineProperty 转换成了 Proxy ,但很少有人去问为什么,本着学习前端知识又可以水一篇文章的想法,于是我又开始水了一篇文章。
1. 性能和灵活性
Vue 2 使用
Object.defineProperty为对象的每个属性定义 getter 和 setter,监控每个属性的变化。但对于嵌套对象,它需要递归地为每层属性进行定义,这会导致性能开销和代码复杂度的增加。因为存在深度遍历,就会存在效率的损失,
而在深度遍历后,对对象进行属性 新增 或者使用 delete 进行删除,delete操作符不会触发set函数)就无法实现响应式。
function isObject(v) {
  return typeof v === 'object' && v != null;
}
function observe(obj) {
  if (!isObject(obj)) {
    return;
  }
  for (const k in obj) {
    let v = obj[k];
    if (isObject(v)) {
      observe(v);
    }
    Object.defineProperty(obj, k, {
      get() {
        console.log(k, '读取', v);
        return v;
      },
      set(val) {
        console.log(k, '更改', val);
        v = val;
      }
    })
  }
}
const obj = {
  name: '小明',
  age: 18,
  love: {
    food: 'apple',
    ball: 'basketball'
  }
}
observe(obj);
obj.love.food = 3;
delete obj.age; // 不会触发Vue 3 使用
Proxy可以直接代理整个对象,自动监听对象内层次嵌套的属性变化,不需要递归地遍历对象的每一层。因此,它对复杂对象的性能优化更加显著。
function isObject(v) {
  return typeof v === 'object' && v != null;
}
const obj = {
  name: '小明',
  age: 18,
  love: {
    food: 'apple',
    ball: 'basketball'
  }
}
function observe(obj) {
  const proxy = new Proxy(obj, {
    get(target, k) {
      let v = target[k];
      // 读取属性的时候,如果是属性是对象才会再进行监听。
      if(isObject(v)) {
        v = observe(v);
      }
      console.log(k, '读取')
      return v;
    },
    set(target, k, v) {
      if (target[k] !== v) {
        target[k] = v;
        console.log(k, '更改')
      }
    },
    deleteProperty(target, k) {
      console.log(k, '删除')
      delete target[k];
    }
  })
  return proxy;
}
const proxy = observe(obj);
proxy.love.ce = 10;
delete proxy.love.ce;2. 对新增和删除属性的支持
Object.defineProperty 无法检测到属性的新增或删除,只能在对象定义时设置已存在的属性。Vue 2 通过
Vue.set和Vue.delete提供了一种手动侦测新增属性的方式,但这种方法较为繁琐且不是完全自动的。Proxy 可以直接监听对象的新增和删除操作,通过
set和deleteProperty拦截器自动响应属性的变化。这样 Vue 3 可以更自然地支持动态属性,提升了响应式的灵活性和简便性。
3. 数组变化的检测
Vue 2 需要用特殊的方式来监控数组的变化(如
push、pop等),因为defineProperty无法直接拦截数组的长度变化或其他方法。Vue 2 中通过重写数组方法来监控数组的变化,但这种做法复杂且影响性能。Proxy 可以直接代理数组对象并捕获其各种操作,无需重写数组方法。它不仅可以侦测到数组内容变化,还可以监控数组的长度变化。这使得 Vue 3 的响应式数组更加高效和直观。
4. 更好的跨平台兼容性
Vue 3 的响应式机制不再依赖特定的属性定义方式,可以在更多平台(如 Web 和移动设备)上有更一致的表现。同时,
Proxy的 API 在现代 JavaScript 引擎中也有较好的支持度和优化,这使得 Vue 3 的响应式系统更具兼容性和效率。
5. 未来可扩展性
Proxy 能够拦截 13 种不同的操作(如
get、set、deleteProperty、has、ownKeys等),Vue 3 只使用了部分功能(主要是get和set)来构建响应式数据系统。这种扩展能力使得 Vue 3 的响应式系统未来可以轻松实现更多的功能和优化,比如在调试模式下增加属性访问的日志等。
6. 总结
Vue 3 引入 Proxy 来替代 Object.defineProperty,解决了 Vue 2 在动态属性、嵌套对象、数组监控等方面的不足,同时减少了性能开销和代码复杂度。Proxy 的使用不仅让 Vue 3 的响应式系统更加高效、灵活,还为未来的功能扩展提供了更多可能性。
- 感谢你赐予我前进的力量
                                
                                
                                    
 
本网站的原创文章部分资源内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系博主邮箱:zzyo.yj@outlook.com 进行删除处理
本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向博主举报
声明:版权所有,违者必究 | 如未注明,均为原创 | 本网站采用CC BY-NC-SA 4.0 协议进行授权
转载:转载请注明原文链接 - Lycoris
            
        
                
