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

在这里插入图片描述

🤍 前端开发工程师(主业)、技术博主(副业)、已过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的特性)在老版本浏览器中也可能存在一些限制。因此,在选择使用哪种拦截机制时,你应该根据具体的项目需求和兼容性考虑做出决策。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

leetcode(平衡二叉树)

https://leetcode.cn/problems/balanced-binary-tree/description/ 这题的思路分成子问题就是计算左右子树的高度然后相减看看是不是大于1的就可以了,所以代码如下 int _isBalanced(struct TreeNode* root) {if(root NULL){return 0;}int leftdepth _isBalanced(…

详细说说vuex

Vuex 是什么 Vuex有几个属性及作用注意事项vuex 使用举例Vuex3和Vuex4有哪些区别 创建 Store 的方式在组件中使用 Store辅助函数的用法响应式的改进Vuex4 支持多例模式 Vuex 是什么 Vuex是一个专门为Vue.js应用设计的状态管理构架,它统一管理和维护各个Vue组件的可…

【后端学前端学习记录】学习计划

1、个人背景 写了足够久的后端了,常用的语言基本上都接触过,没有在工作中写过前端 一直想做一些前端的工作,但是前端技能不足加上自己审美不行,写出的界面总是很丑 所以一直对前端做不好,也没有真正下手。 2、动机 种…

P1 Qt的认识及环境配置

目录 前言 01 下载Qt Creator windows下载安装包拷贝到Linux Linux直接下载 02 Linux 安装Qt 前言 🎬 个人主页:ChenPi 🐻推荐专栏1: 《C_ChenPi的博客-CSDN博客》✨✨✨ 🔥 推荐专栏2: 《Linux C应用编程(概念类…

嵌入式系统未来的发展趋势走向???

人工智能和机器学习应用 模型优化: 为了在资源有限的嵌入式系统上运行,将会看到更多的努力投入到精简、优化和量化模型,以适应边缘计算的环境。 边缘推理: 嵌入式设备将更多地执行本地推理,而不是将所有数据发送到云端…

javaWebssh汽车销售管理系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 java ssh汽车销售管理系统是一套完善的web设计系统(系统采用ssh框架进行设计开发),对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用 B/S模式开发。开发环境为TOMCAT7.…

数字孪生 5G时代的重要应用场景 - 读书笔记

作者:陈根 第1章:数字孪生概述 数字孪生:对物理世界,构建数字化实体,实现了解、分析和优化集成技术:AI、机器学习、大数据分析构成:传感器、数据、集成、分析、促动器(可以人工干预…

Linux/Android之od以字符格式、2进制、8进制、10进制、16进制显示文件内容(三十三)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…

计网 - 白话TCP 三次握手过程

文章目录 概述TCP协议头的格式TCP Finite State Machine (FSM) 状态机三次握手如何在 Linux 系统中查看 TCP 状态 概述 每一个抽象层建立在低一层提供的服务上,并且为高一层提供服务。 我们需要知道 TCP在网络OSI的七层模型中的第四层——Transport层 -----------…

【JVM从入门到实战】(六)类加载器的双亲委派机制

一、双亲委派机制 在Java中如何使用代码的方式去主动加载一个类呢? 方式1:使用Class.forName方法,使用当前类的类加载器去加载指定的类。 方式2:获取到类加载器,通过类加载器的loadClass方法指定某个类加载器加载。 …

windows redis 允许远程访问配置

安装好windows版本的redis,会以服务方式启动,但是不能远程访问,这个时候需要修改配置。redis安装路径下会有2个配置文件,究竟需要怎么修改才能生效呢?看下图 这里的redis服务指定了是redis.windows-service.conf文件&…

# 和 $ 的区别①

# 和 $ 都是为了获取变量的值 # 和 $ 区别 : 使用 # 查询 id 为 1 的内容 如果看不懂代码,就去看<<Mybatis 的操作(结合上文)续集>>,我这里为了简练一点就不多解释了 Select("select * from userInfo where id #{id}")UserInfo selectOne(Integer id…

【C语言】字符串函数及其模拟实现

这是最好的时代&#xff0c;这是最坏的时代&#xff0c;我们一无所有&#xff0c;我们巍然矗立 本文由睡觉待开机原创&#xff0c;未经允许不得转载。 本内容在csdn网站首发 欢迎各位点赞—评论—收藏 如果存在不足之处请评论留言&#xff0c;共同进步&#xff01; 系列文章目录…

TPCTF maze——WP

解包&#xff0c;收集文件信息 先解包 反编译chal.pyc 核心逻辑在maze.so&#xff0c;chal.pyc导入了maze里面的run函数执行&#xff0c;maze是用Cython编译的 用strings查看可以看出是cython3.0.5版本编译的 获取符号表信息的两种方式 使用help读取 我们可以使用这个函数来…

【数据结构】什么是堆?

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 堆的概念及结构 堆的定义如下: n个元素的序列{k1,k2,...,kn}当且仅当满足以下关系时,称之为堆. 或 把这个序列对应的一维数组(即以一维数组作此序列的存储结构)看成是一个…

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

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

【01分数规划】ABC324F

[ABC324F] Beautiful Path - 洛谷 思路 首先看到这个形式很容易想到 01 分数规划&#xff0c;即去二分答案&#xff0c;然后就是转化成 是否存在一个路径使得 sigma b - mid * sigma c > 0 显然只需要改变一下边权&#xff0c;跑一遍最长路即可 #include <bits/stdc.h…

html 中vue3 的setup里调用element plus的弹窗 提示

引入Elementplus之后&#xff0c;在setup&#xff08;&#xff09;方法外面导入ElMessageBox const {ElMessageBox} ElementPlus 源码 &#xff1a; <!DOCTYPE html> <html> <head><meta charset"UTF-8"><!-- import Vue before Elemen…

运筹优化 | 模拟退火求解旅行商问题 | Python实现

"""模拟退火旅行商""" import random import numpy as np import math import time import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False location np.loadtxt(city_location.t…

python-爬取壁纸

代理池的&#xff0c;防止IP 被封 找到图片真实地址 现在看到的只是图片的预览地址 (previews) 1.检查&#xff1a; 2.鼠标变为箭头时查看网页源代码 关于怎样在源代码中找到图片的真实地址 ??? 为什么在源代码界面 ctrl f 时候搜索的是 .png ??? 首先图片地址是以 .j…