Proxy 与 defineProperty 的理解、区别、优势、劣势

news2024/11/28 19:01:58

一、Object.defineProperty()

文档:Object.defineProperty() - JavaScript | MDN 

作用:对一个对象进行操作的方法。可以为一个对象增加一个属性,同时也可以对一个属性进行修改和删除。

它是在 ES5 中引入的,使用了 getter 和 setter 方法来实现 Vue2 的响应式。

1、劣势 

Object.defineProperty() 的问题主要有三个:

  • 不能监听数组的变化 

无法监控到数组下标的变化,导致通过数组下标添加元素,不能实时响应

  • 必须遍历对象的每个属性

只能劫持对象的属性,从而需要对每个对象,每个属性进行遍历。

如果属性值是对象,还需要深度遍历。Proxy 可以劫持整个对象,并返回一个新的对象

  • 必须深层遍历嵌套的对象

2、优势

 兼容性好,支持 IE9

而 Proxy 的存在浏览器兼容性问题,而且无法用 polyfill 磨平

3、代码 
      Object.defineProperty(obj, prop, descriptor);
      // obj 要定义属性的对象
      // prop 要定义或修改的属性的名称
      // descriptor 要定义或修改的属性描述符

      Object.defineProperty(obj, "name", {
        value: "小草莓", // 初始值
        writable: true, // 该属性是否可写入
        enumerable: true, // 该属性是否可被遍历得到(for...in, Object.keys等)
        configurable: true, // 定该属性是否可被删除,且除writable外的其他描述符是否可被修改
        get: function () {},
        set: function (newVal) {},
      });

二、proxy

1、对 Proxy 的理解

Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。

Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。

ES6 入门教程

var obj = new Proxy({}, {
  get: function (target, propKey, receiver) {
    console.log(`getting ${propKey}!`);
    return Reflect.get(target, propKey, receiver);
  },
  set: function (target, propKey, value, receiver) {
    console.log(`setting ${propKey}!`);
    return Reflect.set(target, propKey, value, receiver);
  }
});


obj.count = 1
//  setting count!
++obj.count
//  getting count!
//  setting count!
//  2

上面代码对一个空对象架设了一层拦截,重定义了属性的读取(get)和设置(set)行为

2、语法

ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例

var proxy = new Proxy(target, handler);

第一个参数:target参数表示所要拦截的目标对象

第二个参数:handler参数也是一个对象,用来定制拦截行为它是一个配置对象,对于每一个被代理的操作,需要提供一个对应的处理函数,该函数将拦截对应的操作。

Proxy 对象可以拦截目标对象的任意属性,这使得它很合适用来写 Web 服务的客户端。

3、Proxy的优势
  • 针对对象

针对整个对象,而不是对象的某个属性 ,所以也就不需要对 keys 进行遍历

  • 支持数组

Proxy 不需要对数组的方法进行重载,省去了众多 hack,减少代码量等于减少了维护成本,而且标准的就是最好的

  • Proxy的第二个参数可以有 13 种拦截方法

不限于applyownKeysdeletePropertyhas等等,是Object.defineProperty不具备的

  • Proxy返回的是一个新对象

我们可以只操作新的对象达到目的。而Object.defineProperty只能遍历对象属性直接修改

  • Proxy作为新标准将受到浏览器厂商重点持续的性能优化

也就是传说中的新标准的性能红利

4、使用 proxy 创建一个响应式对象
        import { isObject } from "./util"; // 工具方法

        // 创建一个响应式对象
        export function reactive(target) {
            // 根据不同参数创建不同响应式对象
            return createReactiveObject(target, mutableHandlers);
        }

        // 根据不同参数创建不同响应式对象
        function createReactiveObject(target, baseHandler) {
            if (!isObject(target)) {
                return target;
            }
            const observed = new Proxy(target, baseHandler);
            return observed;
        }

        const get = createGetter();
        const set = createSetter();

        function createGetter() {
            return function get(target, key, receiver) {
                // 对获取的值进行放射
                const res = Reflect.get(target, key, receiver);
                console.log("属性获取", key);
                if (isObject(res)) {
                    // 如果获取的值是对象类型,则返回当前对象的代理对象
                    return reactive(res);
                }
                return res;
            };
        }
        function createSetter() {
            return function set(target, key, value, receiver) {
                const oldValue = target[key];
                const hadKey = hasOwn(target, key);
                const result = Reflect.set(target, key, value, receiver);
                if (!hadKey) {
                    console.log("属性新增", key, value);
                } else if (hasChanged(value, oldValue)) {
                    console.log("属性值被修改", key, value);
                }
                return result;
            };
        }
        export const mutableHandlers = {
            get, // 当获取属性时调用此方法
            set // 当修改属性时调用此方法
        };

三、问题

1、Proxy只会代理对象的第一层,那么 Vue3 又是怎样处理这个问题的呢?

判断当前 Reflect.get 的返回值是否为 Object  ,如果是则再通过 reactive 方法做代理, 这样就实现了深度观测。

2、监测数组的时候可能触发多次get/set,那么如何防止触发多次呢?

我们可以判断 key 是否为当前被代理对象 target 自身属性,也可以判断旧值与新值是否相等,只有满足以上两个条件之一时,才有可能执行 trigger

四、Vue3.0 里为什么要用 Proxy 替代 defineProperty ?

主要是从性能方面考量 

defineProperty:该 API 存在一些局限性,比如对于数组的拦截有问题,为此 Vue 需要专门为数组响应式做一套实现。另外不能拦截那些新增、删除属性。最后 defineProperty 方案在初始化时需要深度递归遍历待处理的对象才能对它进行完全拦截,明显增加了初始化的时间

以上两点在 Proxy 出现之后迎刃而解。

Proxy不仅可以对数组实现拦截,还能对 Map、Set 实现拦截。另外 Proxy 的拦截也是懒处理行为。如果用户没有访问嵌套对象,那么也不会实施拦截,这就让初始化的速度和内存占用都改善了。

Vue的代理也是最开始只代理最外层的对象,在访问的时候去判断是否为一个 object,然后再去用 proxy 包裹

当然 Proxy 是有兼容性问题的,IE 完全不支持,所以如果需要 IE 兼容就不合适 

五、底层拦截原理

六、Proxy 和 Object.defineProperty 的区别?

Vue2 和 Vue3 响应式上有什么区别? / 使用 Object.defineProperty() 来进行数据劫持有什么缺点?_vue 2响应式和vue 3响应式区别-CSDN博客

都可以用来实现 JavaScript 对象的响应式,但是它们有一些区别:

① 实现方式

Proxy 是 ES6 新增的一种特性,使用了一种代理机制来实现响应式。

Object.defineProperty 是在 ES5 中引入的,使用了 getter 和 setter 方法来实现。

② 作用对象

Proxy 可以代理整个对象,包括对象的所有属性、数组的所有元素以及类似数组对象的所有元素。

Object.defineProperty 只能代理对象上定义的属性

③ 监听属性

Proxy 可以监听到新增属性和删除属性的操作

Object.defineProperty 只能监听到已经定义的属性的变化。

④ 性能

由于 Proxy 是 ES6 新增特性,其内部实现采用了更加高效的算法,相对于 Object.defineProperty来说在性能方面有一定的优势。

综上所述,虽然 Object.defineProperty 在 Vue.js 2.x 中用来实现响应式,但是在 Vue.js 3.0 中已经采用了 Proxy 来替代。

这是因为 Proxy 相对于 Object.defineProperty 拥有更优异的性能和更强大的能力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1356744.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

windows机器上安装mysql

0、mysql下载地址 1、参考文章 2、把Data数据目录迁移到其他盘 2.0 首先停止mysql(任务管理器-详细信息-随便找个进程右击进入转入服务,找到MySQL服务,点击停止) 2.1 windows的 mysql默认的data目录在C:\ProgramData\MySQL\MySQ…

【编译原理】期末预习PPT前四章笔记II

看了看学校的ppt,记的比较随意O.o 因为我的考试范围里边没有简答所以概念什么的没怎么记 没有简答只有选择真是太好了嘿嘿嘿 目录 I. 概述(好多字。。) 一、高级语言的分类 1、体裁 2、执行方式 二、各种语言的执行方式 三、编译程序…

52、全连接 - 特征与样本空间的对应关系

上一节说到经过全连接层之后,神经网络学习到的特征,会从隐层特征空间逐步映射到样本空间,这主要是由于全连接层可以融合全局的特征。 在经过全连接层之后,在 ResNet50 这个神经网络中会输出1000个特征的得分值,这1000个特征的得分值,便可以对应到图像的分类。 怎么对应…

一文讲透Linux应用编程—进程原理

文章目录 程序的开始和结束main函数由谁调用?程序是如何结束的?atexit注册进程终止处理函数return、 exit、_exit三者区别 进程环境环境变量进程运行的虚拟空间 进程的正式引入什么是进程?进程ID多进程调度原理 fork创建子进程为什么要创建子…

cnstd使用效果测试

使用参考:https://github.com/breezedeus/CnSTD/tree/master 原理参考:https://cnocr.readthedocs.io/zh/latest/intro-cnstd-cnocr.pdf 模型: 结论: 经过测试, 长文本检测效果不错,短文本可能角度不对 …

MO 2023 年度回顾

PART-ONE 行业态势 随着供需关系的变化,数据库的竞争在经历了 3 年 “百花齐放” 般的发展后,终于在 2023 年进入到了一个相对收拢的阶段。 2023 年,各个数据库厂商间很有默契地在两个方面达成了一致: HTAP 已经成为新一代数据…

vue保姆级教程----深入了解 Vue3计算属性

📢 鸿蒙专栏:想学鸿蒙的,冲 📢 C语言专栏:想学C语言的,冲 📢 VUE专栏:想学VUE的,冲这里 📢 CSS专栏:想学CSS的,冲这里 &#x1f4…

引导过程和服务

宏内核(monolithic kernel):又称单内核和强内核,Unix,Linux把所有系统服务都放到内核里,所有功能集成于同一个程序,分层实现不同功能,系统庞大复杂,Linux其实在单内核内核实现了模块化&#xff…

ROS 系列学习教程(总目录)

ROSLearning 一、ROS概览 1.1 ROS简介 To be continued… 1.2 ROS安装 Ubuntu 安装 ROS 详细教程(以最后一个ROS1版本Noetic为例) 1.3 ROS Hello World ROS创建工作空间添加包并编译 ROS Hello World 1.4 ROS架构 ROS架构:文件系统 …

three.js相机按照指定路线在建筑模型中漫游(支持开始,暂停)

three.js相机按照指定路线在模型中漫游(支持开始,暂停) 关键点 相机运动曲线 // 相机路线 const points [new THREE.Vector3(0, 40, 300),new THREE.Vector3(50, 40, 300),new THREE.Vector3(50, 40, 50),new THREE.Vector3(150, 40, 50),…

在js中foreach、for in和for of 的区别是什么

for in 是一种在 JavaScript 中遍历对象属性的方法,它可以遍历一个对象的所有可枚举属性,但不能遍历数组。 for of 是一种在 JavaScript 中遍历可迭代对象的方法,它可以遍历数组、字符串、Set、Map 等可迭代对象。 foreach 是 JavaScript 中…

华清远见作业第二十一天——IO(第四天)

思维导图&#xff1a; 创建出三个进程完成两个文件之间拷贝工作&#xff0c;子进程1拷贝前一半内容&#xff0c;子进程2拷贝后一半内容&#xff0c;父进程回收子进程的资源。 代码&#xff1a; #include<myhead.h> int main(int argc, const char *argv[]) {if(argc!3)…

GROUP_CONCAT报错解决

有如下表 其中awardee和awardee_unit都是保存的json类型的字符串, awardee是多个人员id, awardee_unit是部门的全路径 查询时要注意转换 需要将name拼接起来合并成一行,直接 GROUP_CONCAT 会报错 百度的大部分答案是修改数据库配置去掉严格模式,如果不方便修改数据库可以这样…

kubernetes(三)

文章目录 1. k8s弹性伸缩1.1 安装heapster监控1.2 弹性伸缩使用和验证 2. 持久化存储2.1 emptyDir 1. k8s弹性伸缩 k8s弹性伸缩&#xff0c;需要附加插件heapster 1.1 安装heapster监控 使用heapster(低版本)可以监控pod压力大不大 使用hpa调节pod数量&#xff0c;自动扩容或…

应用案例——音箱系统的芯片组成

人类的语言交流是人类交互的主要方式&#xff0c;从键盘&#xff0c;鼠标&#xff0c;触屏控制&#xff0c;人机交互的本质始终没有改变&#xff0c;无法完成对话式的交流&#xff0c;而语音交互的出现打破了这一现状&#xff0c;它可以解放双手&#xff0c;甚至解放双眼&#…

双碳目标---碳储量、碳收支、碳循环

以全球变暖为主要特征的气候变化已成为全球性环境问题&#xff0c;对全球可持续发展带来严峻挑战。2015年多国在《巴黎协定》上明确提出缔约方应尽快实现碳达峰和碳中和目标。2019年第49届 IPCC全会明确增加了基于卫星遥感的排放清单校验方法。随着碳中和目标以及全球碳盘点的现…

C练习——定期存取并行

题目&#xff1a;假设银行一年整存零取的月息为1.875%&#xff0c;现在某人手头有一笔钱&#xff0c;他打算在今后5年 中&#xff0c;每年年底取出1000元作为孩子来年的教育金&#xff0c;到第5年孩子毕业时刚好取完这笔钱&#xff0c;请编 程计算第1年年初时他应存入银行多少钱…

基于EMD-SpEn(样本熵)联合小波阈值去噪

代码原理 基于 EMD-SpEn&#xff08;样本熵&#xff09;联合小波阈值去噪方法是一种用于信号降噪的信号处理方法&#xff0c;它结合了经验模态分解 (EMD)、样本熵 (SpEn) 和小波阈值处理技术。 首先&#xff0c;使用 EMD 将原始信号分解为一组称为经验模态函数 (IMFs) 的信号…

基于SpringBoot的在线考试系统源码和论文

网络的广泛应用给生活带来了十分的便利。所以把在线考试管理与现在网络相结合&#xff0c;利用java技术建设在线考试系统&#xff0c;实现在线考试的信息化管理。则对于进一步提高在线考试管理发展&#xff0c;丰富在线考试管理经验能起到不少的促进作用。 在线考试系统能够通…

未来已来,Ai原生应用与人高度结合!学习就在现在?

原生应用&#xff1a;OpenAI™ChatGPT、Baidu.Inc™文心一言 也可以体验CSDN的INSCODE AI&#xff0c;集成多个国内GPT内容。 文章目录 前言----编程语言的未来&#xff1f;一、编程语言的教育1.1 学校所见所闻1.2 开启我们的Ai行程~io&#xff01;1.3 Ai结果评论 二、Ai编程教…