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

2024-01-05 03:28

本文主要是介绍Proxy 与 defineProperty 的理解、区别、优势、劣势,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、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 拥有更优异的性能和更强大的能力。

这篇关于Proxy 与 defineProperty 的理解、区别、优势、劣势的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/571517

相关文章

go 指针接收者和值接收者的区别小结

《go指针接收者和值接收者的区别小结》在Go语言中,值接收者和指针接收者是方法定义中的两种接收者类型,本文主要介绍了go指针接收者和值接收者的区别小结,文中通过示例代码介绍的非常详细,需要的朋友们下... 目录go 指针接收者和值接收者的区别易错点辨析go 指针接收者和值接收者的区别指针接收者和值接收者的

售价599元起! 华为路由器X1/Pro发布 配置与区别一览

《售价599元起!华为路由器X1/Pro发布配置与区别一览》华为路由器X1/Pro发布,有朋友留言问华为路由X1和X1Pro怎么选择,关于这个问题,本期图文将对这二款路由器做了期参数对比,大家看... 华为路由 X1 系列已经正式发布并开启预售,将在 4 月 25 日 10:08 正式开售,两款产品分别为华

深入理解Apache Kafka(分布式流处理平台)

《深入理解ApacheKafka(分布式流处理平台)》ApacheKafka作为现代分布式系统中的核心中间件,为构建高吞吐量、低延迟的数据管道提供了强大支持,本文将深入探讨Kafka的核心概念、架构... 目录引言一、Apache Kafka概述1.1 什么是Kafka?1.2 Kafka的核心概念二、Ka

详解nginx 中location和 proxy_pass的匹配规则

《详解nginx中location和proxy_pass的匹配规则》location是Nginx中用来匹配客户端请求URI的指令,决定如何处理特定路径的请求,它定义了请求的路由规则,后续的配置(如... 目录location 的作用语法示例:location /www.chinasem.cntestproxy

kotlin中const 和val的区别及使用场景分析

《kotlin中const和val的区别及使用场景分析》在Kotlin中,const和val都是用来声明常量的,但它们的使用场景和功能有所不同,下面给大家介绍kotlin中const和val的区别,... 目录kotlin中const 和val的区别1. val:2. const:二 代码示例1 Java

CSS Padding 和 Margin 区别全解析

《CSSPadding和Margin区别全解析》CSS中的padding和margin是两个非常基础且重要的属性,它们用于控制元素周围的空白区域,本文将详细介绍padding和... 目录css Padding 和 Margin 全解析1. Padding: 内边距2. Margin: 外边距3. Padd

Springboot @Autowired和@Resource的区别解析

《Springboot@Autowired和@Resource的区别解析》@Resource是JDK提供的注解,只是Spring在实现上提供了这个注解的功能支持,本文给大家介绍Springboot@... 目录【一】定义【1】@Autowired【2】@Resource【二】区别【1】包含的属性不同【2】@

Java中的String.valueOf()和toString()方法区别小结

《Java中的String.valueOf()和toString()方法区别小结》字符串操作是开发者日常编程任务中不可或缺的一部分,转换为字符串是一种常见需求,其中最常见的就是String.value... 目录String.valueOf()方法方法定义方法实现使用示例使用场景toString()方法方法

分辨率三兄弟LPI、DPI 和 PPI有什么区别? 搞清分辨率的那些事儿

《分辨率三兄弟LPI、DPI和PPI有什么区别?搞清分辨率的那些事儿》分辨率这个东西,真的是让人又爱又恨,为了搞清楚它,我可是翻阅了不少资料,最后发现“小7的背包”的解释最让我茅塞顿开,于是,我... 在谈到分辨率时,我们经常会遇到三个相似的缩写:PPI、DPI 和 LPI。虽然它们看起来差不多,但实际应用

GORM中Model和Table的区别及使用

《GORM中Model和Table的区别及使用》Model和Table是两种与数据库表交互的核心方法,但它们的用途和行为存在著差异,本文主要介绍了GORM中Model和Table的区别及使用,具有一... 目录1. Model 的作用与特点1.1 核心用途1.2 行为特点1.3 示例China编程代码2. Tab