理解 Proxy 和 Object.defineProperty:提升你的 JavaScript 技能(下)

news2024/7/4 5:49:25

在这里插入图片描述

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6
🍨 阿珊和她的猫_CSDN个人主页
🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》
🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入门到实战全面掌握 uni-app》

文章目录

  • Object.defineProperty 的基本概念和用法
    • 解释 Object.defineProperty 的作用和工作原理
    • 展示如何使用 Object.defineProperty 来定义对象的属性
    • 探讨 Object.defineProperty 的一些常见用例,如数据劫持、属性枚举等
  • 比较 proxy 和 Object.defineProperty
    • 分析两者的相似之处和不同之处
  • 总结
    • 总结 proxy 和 Object.defineProperty 的优势和适用场景

Object.defineProperty 的基本概念和用法

解释 Object.defineProperty 的作用和工作原理

Object.defineProperty() 是 JavaScript 中的一个方法,用于定义或修改对象的属性。
它可以用来设置对象的属性是否可枚举、可读写、可配置以及值的获取和设置函数。

Object.defineProperty() 的语法如下:

Object.defineProperty(obj, prop, descriptor)

其中,obj 是要定义属性的对象,prop 是要定义或修改的属性名,descriptor 是一个对象,用于描述属性的特性。

descriptor 对象的属性如下:

  • configurable:是否可配置,即是否可以通过 delete 操作删除属性,或者通过 Object.defineProperty() 重新定义属性。默认为 false
  • enumerable:是否可枚举,即是否可以通过 for...in 循环遍历属性。默认为 false
  • value:属性的值。如果不指定,则默认为 undefined
  • writable:是否可写,即是否可以通过赋值操作修改属性的值。默认为 false
  • get:获取属性值的函数。当访问该属性时,会调用这个函数返回属性值。
  • set:设置属性值的函数。当通过赋值操作修改属性值时,会调用这个函数。

Object.defineProperty() 的工作原理是:它会在对象的原型链上创建一个新的属性,或者修改已有的属性。如果指定了 value 属性,则会直接设置属性的值;如果指定了 getset 函数,则会将这些函数作为属性的获取和设置方法。

通过使用 Object.defineProperty(),可以实现以下功能:

  • 定义只读属性。
  • 定义不可枚举属性。
  • 定义可配置属性。
  • 定义属性的获取和设置方法。

需要注意的是,Object.defineProperty() 只能定义对象的自有属性,而不能定义继承的属性。如果要定义继承的属性,可以使用 Object.getOwnPropertyDescriptor() 方法获取属性的描述符,然后进行修改。

展示如何使用 Object.defineProperty 来定义对象的属性

Object.defineProperty() 方法可以用来直接在一个对象上定义一个新属性,或者修改一个已存在的属性。下面是一些使用 Object.defineProperty() 的例子:

  1. 定义一个不可枚举、可读写的属性:
const obj = {};

// 添加名为 myProperty 的属性,值为 'Hello, World!'
Object.defineProperty(obj, 'myProperty', {
  value: 'Hello, World!',
  enumerable: false,
  writable: true
});

console.log(obj.myProperty); 

在这个例子中,Object.defineProperty() 被用来向 obj 对象添加一个名为 myProperty 的新属性。这个属性的值是 ‘Hello, World!’,它是不可枚举的(即,它不会出现在 for...in 循环中),并且是可读写的。

  1. 定义一个只读属性:
const obj = {};

// 添加名为 myReadOnlyProperty 的属性,值为 'Read Only'
Object.defineProperty(obj, 'myReadOnlyProperty', {
  value: 'Read Only',
  enumerable: true,
  writable: false
});

console.log(obj.myReadOnlyProperty); 
obj.myReadOnlyProperty = '修改失败';
console.log(obj.myReadOnlyProperty); 

在这个例子中,Object.defineProperty() 被用来向 obj 对象添加一个名为 myReadOnlyProperty 的新属性。这个属性的值是 ‘Read Only’,它是可枚举的,但它是只读的,尝试修改它的值会失败。

  1. 定义一个具有 getter 和 setter 的属性:
const obj = {};

// 添加名为 myComputedProperty 的属性,值通过 getter 函数计算得出
Object.defineProperty(obj, 'myComputedProperty', {
  get: function() {
    return this.name + ' ' + this.age;
  },
  enumerable: true
});

obj.name = 'John';
obj.age = 30;

console.log(obj.myComputedProperty); 

在这个例子中,Object.defineProperty() 被用来向 obj 对象添加一个名为 myComputedProperty 的新属性。这个属性的值是通过一个 getter 函数计算得出的,该函数将对象的 nameage 属性组合在一起。这个属性是可枚举的。

你可以根据需要自定义 Object.defineProperty() 的参数,以满足你对对象属性的特定要求。

探讨 Object.defineProperty 的一些常见用例,如数据劫持、属性枚举等

Object.defineProperty 是 JavaScript 中的一个方法,用于定义或修改对象的属性。它可以用来实现一些常见的用例,如数据劫持、属性枚举等。下面是一些常见的用例:

  1. 数据劫持:通过使用 Object.defineProperty,可以在对象的属性上添加自定义的 getset 方法,从而在获取和设置属性值时进行额外的操作,实现数据劫持。这对于实现观察者模式、响应式编程等非常有用。

    下面是一个简单的数据劫持示例,当修改对象的属性时会触发回调函数:

    // 定义一个对象
    const obj = { data: 10 };
    
    // 使用 Object.defineProperty 进行数据劫持
    Object.defineProperty(obj, 'data', {
      get() {
        console.log('读取属性值');
        return this._data;
      },
    
      set(newValue) {
        console.log('设置属性值');
        if (newValue > 100) {
          throw new Error('属性值不能大于 100');
        }
    
        this._data = newValue;
      }
    });
    
    obj.data = 20; 
    console.log(obj.data); 
    
  2. 属性枚举:使用 Object.definePropertyenumerable 属性可以控制属性是否出现在对象的枚举中。默认情况下,对象的属性是可枚举的,但通过将 enumerable 设置为 false,可以使属性不可枚举。

    下面是一个示例,创建一个不可枚举属性:

    const obj = {};
    
    // 创建一个不可枚举属性
    Object.defineProperty(obj, 'mySecret', {
      value: '秘密',
      enumerable: false
    });
    
    // 检查属性是否可枚举
    for (const key in obj) {
      if (obj.hasOwnProperty(key)) {
        console.log(key);
      }
    }
    
    console.log(obj.mySecret); 
    
  3. 属性访问控制:除了 getset 方法外,Object.defineProperty 还可以使用 configurable 属性来控制属性的可配置性。将 configurable 设置为 false 可以防止通过 delete 操作删除属性,或者通过 Object.defineProperty 重新定义属性。

    下面是一个示例,创建一个不可配置的属性:

    const obj = {};
    
    // 创建一个不可配置属性
    Object.defineProperty(obj, 'myProtected', {
      value: '受保护的',
      configurable: false
    });
    
    try {
      // 尝试删除属性
      delete obj.myProtected;
      console.log('属性已删除');
    } catch (error) {
      console.log('删除属性失败:', error.message);
    }
    
    try {
      // 尝试重新定义属性
      Object.defineProperty(obj, 'myProtected', {
        value: '新值'
      });
      console.log('属性已重新定义');
    } catch (error) {
      console.log('重新定义属性失败:', error.message);
    }
    
    console.log(obj.myProtected); 
    

这些是 Object.defineProperty 的一些常见用例。它提供了一种灵活的方式来操作对象的属性,实现一些高级的功能,如数据劫持、属性枚举控制和属性访问控制。

比较 proxy 和 Object.defineProperty

分析两者的相似之处和不同之处

Proxy和Object.defineProperty都是JavaScript中用于拦截对象操作的机制,它们有相似之处,也有不同之处,下面对它们进行比较和分析。

相似之处:

  1. 都可以对对象进行拦截
  2. 都可以拦截属性的读、写和删除操作
  3. 都可以在拦截操作时执行自定义逻辑
  4. 都可以阻止默认操作或修改默认操作的结果。
  5. 都可以监听对象属性变化,以及拦截原型属性访问。
  6. 都可以控制对象的可枚举性、可配置性和可写性。

在这里插入图片描述

不同之处:

  1. Object.defineProperty只能拦截单个属性,而Proxy可以拦截整个对象。
  2. Proxy对拦截的操作范围更广,可以拦截数组操作和函数调用,而Object.defineProperty只能对属性访问进行拦截
  3. Proxy可以动态添加拦截器,而Object.defineProperty直接对属性进行设置
  4. Proxy在处理某些情况下的性能可能会比Object.defineProperty差,特别是当拦截大量属性时。
  5. Object.defineProperty是ES5中引入的,而Proxy是ES6中引入的。

在实际使用中,Object.defineProperty通常用于具体属性的拦截和操作,例如属性的监听,数据劫持等;而Proxy则更适用于对整个对象的拦截和处理,例如实现面向切面编程、缓存、转发等高级功能。但需要注意的是,Proxy虽然功能十分强大,但是并不是所有浏览器都支持,因此在开发时需要根据使用场景和项目需求做出合适的选择,避免因为技术兼容性问题导致项目无法实现。

总结

总结 proxy 和 Object.defineProperty 的优势和适用场景

以下是使用表格总结Proxy和Object.defineProperty的优势和适用场景的示例:

功能ProxyObject.defineProperty
直接拦截对对象的操作
支持拦截的操作范围广泛
可以拦截的操作包括读取、写入、删除等
可以自定义拦截操作的逻辑
可以拦截数组的操作
支持动态添加和删除拦截器
支持对整个对象进行拦截
可以修改拦截的操作结果
替代Object.defineProperty的用法部分替代
对象引用改变是否需要重新设置拦截器需要重新设置不需要重新设置

适用场景:

  • Proxy适用于需要对整个对象进行拦截且拦截的操作范围广泛的场景。它允许自定义拦截逻辑,可以用来实现数据绑定、验证、日志记录等功能。
  • Object.defineProperty适用于只需要对对象的某个属性进行拦截的场景。它可以用来实现对属性的读、写、删除操作进行定制,例如监听属性变化、冻结对象等。

请注意,Proxy是ES6引入的新特性,对于一些需要兼容老版本浏览器的项目可能不适合使用。而Object.defineProperty(作为ES5的特性)在老版本浏览器中也可能存在一些限制。因此,在选择使用哪种拦截机制时,你应该根据具体的项目需求和兼容性考虑做出决策。

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

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

相关文章

华为配置基本QinQ示例

组网需求 如图1所示,网络中有两个企业,企业1有两个分支,企业2有两个分支。这两个企业的各办公地的企业网都分别和运营商网络中的SwitchA和SwitchB相连,且公网中存在其它厂商设备,其外层VLAN Tag的TPID值为0x9100。 现…

ffmpeg编解码——数据包(packet)概念(如何正确处理数据包中的显示时间戳pts与解码时间戳dts关系?)

文章目录 FFmpeg编解码——数据包(Packet)概念1. 数据包(Packet)简介2. 数据包(Packet)在FFmpeg中的应用2.1 从媒体文件读取数据包2.2 向媒体文件写入数据包 3. 数据包(Packet)相关问…

智能优化算法应用:基于鸽群算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用:基于鸽群算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于鸽群算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.鸽群算法4.实验参数设定5.算法结果6.参考文献7.MA…

数据结构-06-散列/哈希表

1-什么是散列表 散列表用的是数组支持按照下标随机访问数据的特性,所以散列表其实就是数组的一种扩展,由数组演化而来。可以说,如果没有数组,就没有散列表。散列表中的元素在数组的位置(index)是通过散列函数得到的。 2-散…

C语言 联合体验证 主机字节序 +枚举

联合体应用&#xff1a;验证当前主机的大小端&#xff08;字节序&#xff09; //验证当前主机的大小端 #include <stdio.h>union MyData {unsigned int data;struct{unsigned char byte0;unsigned char byte1;unsigned char byte2;unsigned char byte3;}byte; };int main…

华为OD机试-传递悄悄话(JavaPythonGo)100%通过率

题意 给定一个二叉树,每个节点上站着一个人,节点数字表示父节点到该节点传递悄悄话需要花费的时间。初始时,根节点所在位置的人有一个悄悄话想要传递给其他人,求二又树所有节点上的人都接收到悄悄话花费的时间。 输入 给定一叉树 09 20-1-1 157-1-1-1-132 注:-1表示空节…

Redis使用——低版本不支持SSUBSCRIBE问题的解决 守护线程daemonize初步

前言 最近在使用redis的使用&#xff0c;报了一个错&#xff0c;ERR unknown command SSUBSCRIBE&#xff0c;后来发现是redis版本的问题。这个似乎是redis的发布订阅模式相关的配置。 目录 前言引出低版本不支持SSUBSCRIBE报错unknown command SSUBSCRIBE检查docker版本拉取指…

薅github的羊毛-用pages建自己的博客或资源站 - 博客工具 - 2/2

笔者调研了好多个静态博客工具&#xff0c;最后锁定Hexo了&#xff0c;但不等于其他博客不行。我只吐槽两个 Hugo - 难用Gridea - 简直就是骗钱的&#xff0c;我交钱用不了 theme没有链接&#xff0c;同步也同步不了&#xff0c;估计以前是可以&#xff0c;现在经营不下去&…

C语言结构体和位段

自定义类型&#xff1a;结构体及联合和枚举 一.结构体类型的声明1.1 结构体的概念1.2结构的声明1.3特殊的声明1.4结构体的自引用1.5可以使用typedef重命名 二.结构体变量的创建和初始化2.1结构体变量的初始化使用{}2.2初始化&#xff1a;定义变量的同时赋初值。2.3结构体嵌套及…

基于FFmpeg,实现播放器功能

一、客户端选择音视频文件 MainActivity package com.anniljing.ffmpegnative;import android.Manifest; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.Ur…

【python笔记】requests模块基础总结

前言 菜某笔记总结&#xff0c;如有错误请指正。&#xff08;抱歉可能我用渗透的靶场做的功能演示&#xff0c;让单纯想看爬虫整理的朋友不好理解&#xff0c;主要看一下requests库的写法吧&#xff0c;关于sql靶场&#xff0c;文件上传靶场什么的都当做网站的名字吧&#xff…

无法打开源文件“opencv2/opencv.hpp“

如图报错&#xff0c;看见就非常高血压 解决方案&#xff1a; 1.打开项目属性 第二步&#xff0c;注意你如果跑的是Debug&#xff0c;那么你在项目属性里面设置的必须选择Debug模式&#xff0c;跑的Release模式&#xff0c;则你必须要设置相应的Release模式&#xff01;否则你…

【金华模式】双龙旅游引燃露营设计和文旅产融合新方式

&#xff08;中国国际教育电视台 黎明&#xff09;金华双龙风景旅游区位于浙江省金华市北郊的金华山麓&#xff0c;是一处融自然山水、溶洞群景观、科普探险、康体休闲、避暑度假、观光朝圣于一体的景区。旅游区人文积淀深厚&#xff0c;道、儒、释文化兼收并蓄&#xff0c;东汉…

Android Studio的代码笔记--Adapter+GridView学习

AdapterGridView学习 AdapterGridViewSimpleAdapterGridViewactivity_main.xmlappicon.xmlMainActivity 自定义BaseAdapterGridView已下载应用PackageInfoAppAdapterMainActivity2 其他获取已下载应用信息函数获取所有应用信息函数ImageView产生圆角的方法背景设置很渐变设置选…

二、远程控制树莓派(在用一个Wifi下)

VNC是一个图形桌面共享系统&#xff0c;利用一台计算机或移动设备&#xff08;运行VNC查看器&#xff09;远程控制另一台计算机&#xff08;运行VNC服务器&#xff09;的桌面。 Step1&#xff1a;树莓派&#xff1a;安装VNC服务器&#xff08;树莓派自带&#xff09; 打开方式…

从 Android 手机恢复删除的数据的10个有效工具

您是否曾经在 Android 手机上遇到过数据丢失的情况&#xff0c;即您拍摄的瞬间或其他数据意外丢失&#xff1f; 就我而言&#xff0c;我多次遇到过此类数据丢失的情况&#xff0c;相信我&#xff0c;没有什么比从手机中丢失所有重要数据更严重的了。这就像一场噩梦&#xff0c…

102基于matlab的PCA+ELM和PCA+PSO-ELM的费用估计

基于matlab的PCAELM和PCAPSO-ELM的费用估计&#xff0c;输出输出两者的预测误差并进行比较&#xff0c;输出优化后的迭代曲线。数据可更换自己的&#xff0c;程序已调通&#xff0c;可直接运行。 102matlab PCAPSOELM (xiaohongshu.com)

数据标注公司如何确保数据安全?景联文科技多维度提供保障

数据标注公司通常拥有大量的AI数据和用户数据&#xff0c;保护数据安全是数据标注公司的重要任务。 数据标注公司确保标注数据的安全可以从制度、人员、工具等多个方面入手&#xff0c;建立完善的安全管理体系和审计机制&#xff0c;加强应急预案和备份机制的建立&#xff0c;以…

Docker容器:docker推送镜像至Harbor

目录 1、Harbor创建项目 2、进入test项目&#xff0c;查看推送命令 3、在docker服务器上准备一个镜像 4、修改docker客户端配置 5、重启docker服务 6、docker登录Harbor 7、docker镜像推送到Harbor 1、Harbor创建项目 2、进入test项目&#xff0c;查看推送命令 3、在dock…

路由器静态路由的配置

路由器静态路由的配置步骤如下&#xff1a; 进入系统视图。输入命令sys进入系统视图。配置路由器的接口IP地址。命令格式为int g0/0/0&#xff0c;其中g0/0/0表示路由器的接口&#xff0c;可以根据实际情况进行修改。然后使用命令ip add配置接口的IP地址。配置下一跳地址。在静…