• Object.defineProperty 与 Proxy 有什么区别?


    大家好,我是前端西瓜哥,今天来看看 Object.defineProperty 和 Proxy 的区别。

    我们先简单看看 Object.defineProperty 和 Proxy 的用法。

    Object.defineProperty

    Object.defineProperty 可以在对象上修改或新增属性,并设置它的属性描述符,然后返回这个对象。

    这个方法依次接受:

    1. 要改变的对象

    2. 属性名

    3. 属性描述符

    const obj = {};
    
    Object.defineProperty(obj, 'a', {
      value: '前端西瓜哥'
    });
    
    console.log(obj.a);
    // 前端西瓜哥
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    属性描述符是一个对象,有以下几个配置:

    1. value:属性值,默认为 undefined;

    2. configurable:属性描述符能否改变,以及属性能否被删除(通过 delete 关键字)。但 false 下,writable 可以单向变成 false,以及 value 可以改为任何值。默认为 false;

    3. writable:值能否被修改,默认为 false;

    4. get:getter 函数,当属性被读取时,调用该函数并使用它的返回值作为读取值。我们可以通过 this 访问当前对象。get/set 不能和 value/writable 共存,因为它们互相冲突。默认值为 undefined;

    5. set:setter 函数,当属性被修改时,设置的新值会传给 setter 函数,我们就可以将这个新值缓存起来,默认值为 undefined;

    6. enumerable:是否为可枚举属性,可枚举代表可以被 for…in 等 API 读取到。默认值为 false。

    属性描述符还是有点复杂的,想深入学习可以去看看 MDN 文档。

    Object.defineProperty 可以实现 代理,当我们通过 obj.key 的形式读取或设置值时,就可以通过 setter 和 getter 去执行一些副作用。

    Vue2 正是用这个方式来实现数据的响应式,按需更新视图的。

    Proxy

    Proxy 用于创建对象的代理。

    我们通过 new Proxy 来创建代理对象,构造函数接受:

    1. 被代理的对象

    2. handler 对象,其实就是一个配置对象,可以设置被代理对象的各种行为的代理,这些行为一般都是函数,称为 trap(捕捉器)。比如对象的属性被设置或修改时触发特定的函数。

    看个例子:

    const obj = {};
    
    const proxyObj = new Proxy(obj, {
      get(target, prop, receiver) {
        return '前端西瓜哥' + prop;
      }
    });
    
    console.log(proxyObj.handsome);
    // 前端西瓜哥handsome
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    当访问代理对象的属性时,就会执行该 get 函数。

    其中 target 为被代理对象,prop 为被访问的属性名,recevier 为代理对象。然后 get 函数的返回值就是最后读取到的值。

    这个例子中,当访问一个属性时,会返回一个加了前缀的属性名。

    除了 get,Proxy 还可以代理其他的行为,比如设置属性的捕捉器 set、构造函数的捕捉器 construct、delete 操作符的捕捉器 deleteProperty 等等。

    非常多,就不一个个说明了,读者可自行前往 MDN 文档学习。

    Vue3 抛弃了 defineProperty,使用了 Proxy 来代理对象属性。

    defineProperty 和 Proxy 的区别

    defineProperty 和 Proxy 都可以对属性进行代理。

    代理的粒度不同

    defineProperty 只能代理属性,Proxy 代理的是对象

    也就是说,如果想代理对象的所有属性,defineProperty 需要遍历属性一个个加 setter 和 getter。

    而 Proxy 只需要配置一个可以获取属性名参数的函数即可。

    当然,如果出现嵌套的对象,Proxy 也是要递归进行代理的,但可以做惰性代理,即用到嵌套对象时再创建对应的 Proxy。

    是否破坏原对象

    defineProperty 的代理行为是在破坏原对象的基础上实现的,它通常会将原本的 value 变成了 setter 和 getter。

    Proxy 则不会破坏原对象,只是在原对象上覆盖了一层。当新增属性时,希望属性被代理,defineProperty 需要显式调用该 API,而 Proxy 则可以直接用 obj.key = val的形式;

    代理数组属性

    defineProperty 不适合监听数组属性,因为数组长度可能很大,比如几百万,一个个对索引使用 defineProperty 是无法接受的。

    一种方式是重写数组的 API 方法(比如 splice),通过它们来实现代理,但它是有缺陷的:直接用 arr[1] = 100 无法触发代理。这是 Vue2 的做法。

    另外,我们无法对数组的 length 做代理。这暴露了 defineProperty 的一个缺陷:设置了 configurable 为 false 的属性无法进行代理。数组的 length 就是这种情况。

    图片

    Proxy 则没有这个问题,它只需要设置一个 setter 和 getter,在属性变化时,能够在函数参数上拿到索引值。

    代理范围

    defineProperty 只能代理属性的 get 和 set。

    Proxy 还能代理其他的行为,比如 delete 和 handler.getPrototypeOf() 等方法。

    兼容性

    Proxy 是 ES6 新增的特性,兼容性不如 defineProperty。

    IE 不支持 Proxy。

    且 Proxy 不能被完美 polyfill,因为它是在编程语言的层面上的修改。

    Proxy 貌似还会有些性能问题,但作为标准,浏览器会持续做重点性能优化。

    结尾

    总的来看,Proxy 相比 defineProperty 更适合做代理。

    我是前端西瓜哥,欢迎关注我,学习更多前端知识。

  • 相关阅读:
    在线音乐播放项目——BY音乐
    python计算阶层
    抗肿瘤靶向药物丨小分子化合物 or 单克隆抗体?- MedChemExpress
    基于粒子群算法的排课系统,基于PSO的排课系统,粒子群算法原理,粒子群算法流程
    bare Git 仓库是什么?
    Ei & Scopus检索 | 2024年第三届能源与环境工程国际会议(CFEEE 2024)
    BUGKU CTF (Crypto第一篇)
    CAD二次开发LineSegment2d
    SpringCloud学习笔记(五) Ribbon 负载均衡服务调用
    K8S排水错误汇总(忽略DaemonSet管理Pod、Mysql集群排水报错、Mongo集群排水报错)
  • 原文地址:https://blog.csdn.net/fe_watermelon/article/details/126750208