Proxy vs Object.defineProperty:哪种对象拦截机制更适合你?

news2024/9/22 1:12:17

在这里插入图片描述

文章目录

  • 简述版
  • 详解版
    • 相同点
    • 不同点
      • 1. 功能不同
      • 2. 语法和使用方式不同
      • 3. 支持程度不同
      • 4. 性能差异

简述版

ProxyObject.defineProperty 是 JavaScript 中用于实现对象拦截和代理的两种不同机制

Object.defineProperty 是一种在对象上定义新属性或修改现有属性的方式。
它接受三个参数:目标对象、属性名和属性描述符对象。
通过定义属性描述符对象,可以控制属性的行为,例如设置属性的值、可写性、可枚举性和可配置性等。
使用 Object.defineProperty 可以对对象的单个属性进行拦截,并在属性被访问、赋值或删除时执行自定义的逻辑,但它只能拦截单个属性操作。

示例:

const obj = {};
let value;

Object.defineProperty(obj, 'name', {
  get() {
    console.log('Getting name');
    return value;
  },
  set(newValue) {
    console.log('Setting name to', newValue);
    value = newValue;
  }
});

obj.name = 'Alice'; // Setting name to Alice
console.log(obj.name); // Getting name, Alice

Proxy 则是一种更强大的代理机制,它可以拦截并改变对目标对象的各种操作,包括属性的读取、赋值、删除、函数调用等。通过创建一个代理对象,可以通过在代理对象上定义各种拦截器(handler)来捕获并处理对目标对象的操作。代理对象中的拦截器提供了对底层操作的细粒度控制,并可以以声明式的方式进行操作。

示例:

const obj = {
  name: 'Alice'
};

const handler = {
  get(target, prop, receiver) {
    console.log('Getting', prop);
    return Reflect.get(target, prop, receiver);
  },
  set(target, prop, value, receiver) {
    console.log('Setting', prop, 'to', value);
    return Reflect.set(target, prop, value, receiver);
  }
};

const proxy = new Proxy(obj, handler);

proxy.name = 'Bob'; // Setting name to Bob
console.log(proxy.name); // Getting name, Bob

可以看到,通过 Proxy,我们可以定义拦截器来控制对目标对象的各种操作。当访问或修改属性时,拦截器会被触发并执行相应的自定义逻辑。相比之下,Object.defineProperty 只能拦截单个属性的读取、赋值和删除,并且需要显式地为每个属性定义拦截逻辑。

总结来说,Object.defineProperty 是一种定义和拦截对象属性的简单方式,而 Proxy 提供了更灵活和强大的机制,可以拦截和改变更多类型的对象操作。在需要对整个对象或多个属性进行拦截和代理时,Proxy 是更常用和推荐的选择。

详解版

Proxy 和 Object.defineProperty 的异同点可以概括如下:

相同点

  1. 都可以用来拦截和控制对象的访问、赋值和删除操作
  2. 都可以定义自定义的行为逻辑来处理拦截操作

不同点

1. 功能不同

Object.defineProperty 可以对单个属性进行拦截,而 Proxy 可以对整个对象进行拦截,并且可以拦截更多类型的操作,如函数调用等。

当涉及到功能上的区别时,下面的代码示例将更详细地展示 Proxy 和 Object.defineProperty 在拦截和代理对象操作方面的不同行为。

首先,我们将使用 Object.defineProperty 来拦截和代理单个属性的读取和写入:

const obj = {};
let value;

Object.defineProperty(obj, 'name', {
  get() {
    console.log('Getting name');
    return value;
  },
  set(newValue) {
    console.log('Setting name to', newValue);
    value = newValue;
  }
});

obj.name = 'Alice'; // Setting name to Alice
console.log(obj.name); // Getting name, Alice

现在,我们将使用 Proxy 来拦截和代理整个对象的操作:

const obj = {
  name: 'Alice',
  age: 25
};

const handler = {
  get(target, prop, receiver) {
    console.log('Getting', prop);
    return Reflect.get(target, prop, receiver);
  },
  set(target, prop, value, receiver) {
    console.log('Setting', prop, 'to', value);
    return Reflect.set(target, prop, value, receiver);
  },
  deleteProperty(target, prop) {
    console.log('Deleting', prop);
    return Reflect.deleteProperty(target, prop);
  }
};

const proxy = new Proxy(obj, handler);

proxy.name = 'Bob'; // Setting name to Bob
console.log(proxy.name); // Getting name, Bob

delete proxy.age; // Deleting age
console.log(proxy.age); // undefined

从以上示例中可以看出,在功能上的区别点包括:

  1. Object.defineProperty 可以用来定义单个属性的拦截,通过设置 get 和 set 来拦截属性的读取和赋值。而 Proxy 可以拦截整个对象的操作,包括属性的访问、赋值和删除等。
  2. Object.defineProperty 需要显式地为每个属性设置拦截逻辑,而 Proxy 是通过定义代理对象上的拦截器函数来处理所有操作,使得代码更集中和声明式。
  3. Proxy 的拦截器函数可以拦截各种类型的操作,如函数调用、属性枚举等,而 Object.defineProperty 不能拦截其他类型的操作。
  4. Proxy 在捕获和处理对象操作时具有更多的灵活性,但相对来说性能也稍逊于 Object.defineProperty。

这些示例展示了 Proxy 和 Object.defineProperty 在功能上的区别,以及它们在拦截和代理对象操作方面的不同行为。

2. 语法和使用方式不同

Object.defineProperty 是通过设置属性描述符对象来定义拦截行为,而 Proxy 是创建一个代理对象并定义拦截器函数来实现拦截。

下面是一些代码示例,用于详细说明 Proxy 和 Object.defineProperty 在语法和使用方式上的差异:

  1. 使用 Object.defineProperty:
const obj = {};

Object.defineProperty(obj, 'name', {
  value: 'Alice',
  writable: true,
  enumerable: true,
  configurable: true
});

console.log(obj.name); // Alice

obj.name = 'Bob'; // 此处将成功修改属性值

for (let key in obj) {
  console.log(key); // name
}

delete obj.name; // 此处删除成功

console.log(obj.name); // undefined
  1. 使用 Proxy:
const obj = { name: 'Alice' };

const handler = {
  get(target, prop) {
    console.log('Getting', prop);
    return target[prop];
  },
  set(target, prop, value) {
    console.log('Setting', prop, 'to', value);
    target[prop] = value;
  },
  deleteProperty(target, prop) {
    console.log('Deleting', prop);
    delete target[prop];
  }
};

const proxy = new Proxy(obj, handler);

console.log(proxy.name); // Getting name, Alice

proxy.name = 'Bob'; // Setting name to Bob

for (let key in proxy) {
  console.log(key); // 此处不会输出任何内容
}

delete proxy.name; // Deleting name

console.log(proxy.name); // Getting name, undefined

从上述示例中可以看出,在语法和使用方式上的不同点包括:

  • Object.defineProperty 是通过设置属性描述符对象来定义拦截行为。通过直接操作对象的属性描述符,可以控制属性的可写性、可枚举性、可配置性等。
  • Proxy 是通过创建代理对象并定义拦截器函数来实现拦截。代理对象会在访问和操作时调用拦截器函数,根据不同的拦截行为进行处理。Proxy 可以更灵活地处理各种类型的操作,如属性的读取、设置、删除,函数调用等。
  • 使用 Object.defineProperty 需要显式为每个属性设置拦截行为,繁琐且不灵活。而 Proxy 通过统一的拦截器函数处理所有操作,提供了更集中和声明式的方式来定义拦截行为。
  • 在语法上,Object.defineProperty 在设置属性描述符时可以一次性定义多个属性,而 Proxy 则是针对整个对象进行拦截操作。
  • Object.defineProperty 是较早的 JavaScript 特性,较低版本的 JavaScript 中也可使用。而 Proxy 是 ES6 中新增的特性,可能在某些较旧的 JavaScript 环境中不被支持。

这些示例展示了 Proxy 和 Object.defineProperty 在语法和使用方式上的差异,以及它们在定义拦截行为方面的不同方式。

3. 支持程度不同

Object.defineProperty 在较低版本的 JavaScript 中支持较好,而 Proxy 是 ES6 中新增的特性,可能在某些较旧的 JavaScript 环境中不被支持。

Proxy 和 Object.defineProperty 在支持程度上有一些差异。下面是一些代码示例,用于详细说明它们在支持程度方面的不同表现:

  1. Proxy 的支持程度:
if (typeof Proxy !== 'undefined') {
  const obj = { name: 'Alice' };
  const handler = {};

  const proxy = new Proxy(obj, handler);
  console.log(proxy.name); // Alice
} else {
  console.log('Proxy is not supported');
}
  1. Object.defineProperty 的支持程度:
const obj = {};
if (typeof Object.defineProperty !== 'undefined') {
  Object.defineProperty(obj, 'name', {
    value: 'Alice',
    writable: true,
    enumerable: true,
    configurable: true
  });
  console.log(obj.name); // Alice
} else {
  console.log('Object.defineProperty is not supported');
}

上述示例展示了对 Proxy 和 Object.defineProperty 进行支持性检查并执行相应的代码。通过检查这两个功能是否被定义(即类型是否为 ‘undefined’),我们可以确定它们是否受到支持。

请注意,Proxy 是 ES6 中新增的功能,因此在较旧的 JavaScript 环境中可能不受支持。而 Object.defineProperty 是较早的 JavaScript 特性,基本上支持所有的现代浏览器。

通过执行上述代码并观察输出结果,您可以了解当前环境对 Proxy 和 Object.defineProperty 的支持程度,并根据需要采取适当的兼容性处理。

4. 性能差异

通常情况下,Object.defineProperty 的性能比 Proxy高效因为 Proxy 需要动态地捕获和处理对象的每个操作

Proxy 和 Object.defineProperty 在性能方面也存在一些差异。下面是一些代码示例,用于详细说明它们在性能上的表现差异:

  1. Proxy 的性能表现:
const obj = { name: 'Alice' };
const handler = {};

const proxy = new Proxy(obj, handler);

console.time('Proxy');
for (let i = 0; i < 10000; i++) {
  console.log(proxy.name);
}
console.timeEnd('Proxy');
  1. Object.defineProperty 的性能表现:
const obj = {};
Object.defineProperty(obj, 'name', {
  value: 'Alice',
  writable: true,
  enumerable: true,
  configurable: true
});

console.time('Object.defineProperty');
for (let i = 0; i < 10000; i++) {
  console.log(obj.name);
}
console.timeEnd('Object.defineProperty');

上述示例使用 console.time 和 console.timeEnd 来计算两种方式执行访问属性的性能。通过循环执行访问属性的操作,并使用计时器记录执行时间。

执行上述代码后,您可以观察到输出结果中的执行时间。根据测试结果,您可能会发现以下差异:

  • Proxy 可以通过拦截器函数灵活地处理各种操作,但由于其动态代理的特性,它通常比 Object.defineProperty 操作较慢。
  • Object.defineProperty 直接在对象上定义属性描述符,因此在直接访问属性时可能会更快。

然而,这个性能差异可能因 JavaScript 引擎的实现而异。在实际应用中,性能差异的影响可能会因具体的场景和操作方式而有所不同。

总结而言,Proxy 的动态代理特性可能会导致性能较低,而 Object.defineProperty 在直接访问属性时可能性能较好。在选择使用哪种方式时,请根据具体情况进行评估并进行性能测试,以确保您选择的方式最适合您的应用需求。

综上所述,Object.defineProperty 适用于对单个属性进行简单拦截和控制,而 Proxy 则更适合对整个对象进行复杂的拦截和代理。选择哪种机制取决于具体的需求和使用场景。

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

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

相关文章

eNSP-DHCP全局配置和接口配置

eNSP-DHCP全局配置和接口配置 文章目录 eNSP-DHCP全局配置和接口配置一、题目要求二、题目分析三、拓扑结构搭建四、基本配置五、测试验证 一、题目要求 要求 &#xff1a; 1 、GE0/0/0 口所在广播域使用全局配置模式 2 、 GE0/0/1 口所在广播域使用接口配置模式 3 、 租期时间…

远古 Windows 98 SE 和 putty 0.63 连接 SSH

远古 Windows 98 SE 和 putty 0.63 连接 SSH 不忘初心一、故障表现二、产生原因三、解决办法四、重启 SSHD 服务生交配置参考 作者&#xff1a;高玉涵 时间&#xff1a;2023.7.1 操作系统&#xff1a; Windows 98 第二版 4.10.2222 A Linux version 5.19.0-32-generic (build…

慧灵六轴机械臂和电动夹爪,适配全自动粉面烘焙机器人

近日&#xff0c;慧灵科技HITBOT推出的六轴机械臂和平行电动夹爪等产品&#xff0c;出现在一台全自动粉面&烘焙机器&#xff0c;为煮饺子、云吞、面条的传统方式注入了现代科技的力量。这台机器结合了先进的六轴机械臂产品和精密的智能控制系统&#xff0c;能够在短时间内完…

CleanMyMac X中文版Mac电脑系统清理工具使用测评

有些人可能会说&#xff0c;mac系统根本就不需要清理&#xff0c;但是真正到你磁盘快满的时候就不是这种想法了&#xff0c;不管什么系统&#xff0c;它都会缓存一些系统、用户等文件&#xff0c;可能当时能够帮上大忙&#xff0c;能够在操作的时候更快、更便捷&#xff0c;但是…

78、基于STM32单片机步进电机速度调速控制系统设计(程序+原理图+PCB源文件+参考论文+开题报告+流程图+元器件清单等)

摘 要 伴随着时代的快速发展&#xff0c;单片机的应用也越来越广泛&#xff0c;促进了微电子和计算机的快速发展。我们日常生活中步进电机扮演着很重要的角色在我们身边随处可以见。因为步进电机本身的结构组成相对于比较简单、价格也比较便宜廉价。比如压榨机&#xff0c;打印…

【FATE联邦学习】get out put data报错output dir = result[“directory“]KeyError:directory“

报错信息不清不楚的。 经过几个周的排查&#xff0c;有以下原因&#xff1a; 自定义的trainer里面的predict函数没有返回有效的返回值。也有可能是自定义的网络没有使用softmax结尾。&#xff08;若没有&#xff0c;加上即可&#xff09; 应该是二者满足其一就可以。。因为有…

利用spleeter库实现人声和音乐分离(踩过的坑及解决方法)

0&#xff1a;起因 事情的起因是&#xff1a;想用一首歌的伴奏剪视频&#xff0c;但找遍各大平台&#xff0c;都只有原曲&#xff0c;没有伴奏。能找到的进行人声和背景音乐分离的软件都要收费&#xff0c;最后决定用spleeter库&#xff0c;尝试进行音频分离。 1&#xff1a;…

DAY3、DAY4(路飞)

字典 因为key不能为变量 只能为不可变的值 字典的key必须是唯一的 不然后面的值会吧前面的值覆盖 字典取值只能一个一个取 且只能通过key查询value 不能反过来 d.items就是变成了列表里 元祖的形式 这种取值是最推荐的。第三种比第二种推荐的方式 是因为第2种取值会先转…

Redis实战篇(四)

六.秒杀优化 6.1 秒杀优化-异步秒杀思路 之前的下单流程 当用户发起请求&#xff0c;此时会请求nginx&#xff0c;nginx会访问到tomcat&#xff0c;而tomcat中的程序&#xff0c;会进行串行操作&#xff0c;分成如下几个步骤 1、查询优惠卷 2、判断秒杀库存是否足够 3、查…

【NoSQL之 Redis配置】

目录 一、关系数据库与非关系型数据库1、关系型数据库和非关系型数据库区别&#xff08;1&#xff09;数据存储方式不同&#xff08;2&#xff09;扩展方式不同&#xff08;3&#xff09;对事务性的支持不同 2、非关系型数据库产生背景总结 二、Redis简介1、Redis 具有以下几个…

碳排放预测模型 | Python实现基于DT决策树的碳排放预测模型

文章目录 效果一览文章概述研究内容源码设计参考资料效果一览 文章概述 碳排放预测模型 | Python实现基于DT决策树的碳排放预测模型 研究内容 碳排放被认为是全球变暖的最主要原因之一。 该项目旨在提供各国碳排放未来趋势的概述以及未来十年的全球趋势预测。 其方法是分析这些…

迁移Notes最近应用和工作台图标到Nomad Web中

大家好&#xff0c;才是真的好。 今天我们分享一个十分有趣的技术话题&#xff0c;就是将Notes客户机&#xff08;MacOS和Windows&#xff09;上的最近访问应用和工作台图标迁移到Nomad Web中&#xff0c;这样用户就可以在Nomad Web和Notes中获得一致的使用体验。 毕竟Nomad …

maven项目如何引入项目本地jar包

目录 背景操作 背景 由于项目需要&#xff0c;对jar包中的内容进行了一点改变&#xff0c;但是由于不熟悉公司maven仓库发布流程&#xff0c;所以就把jar包放到了项目中&#xff0c;那就需要将本地jar包交给maven管理 操作 在项目中新建目录lib&#xff0c;然后将jar包放在其…

Xilinx ZYNQ系列10款型号IDCODE汇总(2023年7月最新版)

ZYNQ系列产品选型手册&#xff1a;zynq-7000-product-selection-guide /* Zynq Devices. */ #define IDCODE_XC7Z007 0x03723093 #define IDCODE_XC7Z010 0x03722093 #define IDCODE_XC7Z012 0x0373C093 #define IDCODE_XC7Z014 0x03728093 #defi…

Linux学习之服务管理工具systemctl

在CentOS 7中有两种服务集中管理工具&#xff1a; service systemctl /etc/init.d/中放着service的启动脚本。比如network这个脚本里边就有网络服务的启动脚本&#xff0c;cat network | wc -l可以看到这个文件中有264行内容。 /usr/lib/systemd/system下放着systemctl的启动脚…

Redis————主从架构

主从架构搭建 单机多实例 粗制一份redis.conf文件 将相关配置修改为如下值&#xff1a; port 与主节点端口后不相同即可 pidfile pid进程号保存文件pidfile的路径 logfile 日志文件名称 dir 指定数据存放目录 #需要注释掉bind #bind 127.0.0.1&#xff08;bind绑定的是自己机…

Spring Boot 中的 RabbitMQ 的消息接收配置是什么,原理,如何使用

Spring Boot 中的 RabbitMQ 的消息接收配置是什么&#xff0c;原理&#xff0c;如何使用 RabbitMQ 是一个流行的消息队列系统&#xff0c;它可以用于在应用程序之间传递消息。Spring Boot 提供了对 RabbitMQ 的支持&#xff0c;我们可以使用 Spring Boot 中的 RabbitMQ 消息接…

从0到1精通自动化测试,pytest自动化测试框架,allure标记用例级别severity(二十一)

目录 一、前言 二、用例等级 三、pytest用例 四、统计缺陷 五、allure命令行参数allure-severities 一、前言 我们在做功能测试的时候&#xff0c;执行完一轮测试用例&#xff0c;输出测试报告的时候&#xff0c;会有统计缺陷的数量和等级 在做自动化测试的过程中&#…

SpringBoot3【② Web开发】

SpringBoot3-Web开发 SpringBoot的Web开发能力&#xff0c;由SpringMVC提供。 0. WebMvcAutoConfiguration原理 1. 生效条件 AutoConfiguration(after { DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,ValidationAutoConfiguration.clas…

12-C++算法笔记-递推

&#x1f4d6; 引入 让我们从一个有趣的例子开始&#xff0c;棋盘放米的问题。假设有一个 8 8 8\times8 88 的棋盘&#xff0c;皇帝想要奖赏一位大臣。大臣提出的要求是在棋盘上按如下规则领赏&#xff1a;第一个格子上放一粒米&#xff0c;随后的每个格子都放置前一个格子上…