属性描述符初探——Vue实现数据劫持的基础

目录

属性描述符——Vue实现数据劫持的基础

一、属性描述符是什么?

​编辑

1.1、属性描述符示例

1.2、用属性描述符定义属性及获取对象的属性描述符

1.3、带有读取器和设置器的属性描述符

二、使用属性描述符的情景

2.1、封装和数据隐藏

        使用getter和setter来封装一个对象的内部状态,防止直接访问和修改。

2.2、 创建只读属性

        通过设置writable为false,可以创建一个不允许修改的属性。

 2.3、验证属性赋值

        在setter中添加逻辑来验证属性值,确保它们满足特定条件。

三、情景:如果属性描述符中writable为false,但是写了set函数

四、总结与相关资源


        请注意,本文讲述的是JS中的属性描述符,不是Python中的属性描述符

属性描述符——Vue实现数据劫持的基础

一、属性描述符是什么?

        属性描述符(Property Descriptor)在JavaScript中是一个特殊的对象,它定义了对象属性的行为和特性。

        属性描述符是一个对象,它通常包含以下几个属性:

  • value:属性的值。这是一个数据属性的特性,用于存储属性值。
  • writable:一个布尔值,表示属性的值是否可被修改。如果设置为false,属性值将不可修改。
  • get:一个函数,当访问属性时调用,用于获取属性值。这是一个访问器属性的特性。
  • set:一个函数,当设置属性值时调用,用于设置属性值。这是一个访问器属性的特性。
  • enumerable:一个布尔值,表示属性是否可被枚举,默认为false。如果设置为true,则属性会显示在for-in循环和Object.keys()的结果中。
  • configurable:一个布尔值,表示属性的属性描述符是否可以被改变,以及属性是否可以被删除。如果设置为false,属性将不能被删除,且其属性描述符不能被改变。

         属性描述符的属性树如下:

1.1、属性描述符示例

        属性描述符示例如下:

let descriptor = {
  value: 42,
  writable: true,
  enumerable: true,
  configurable: true
};

        在这个例子中,descriptor是一个属性描述符对象,它定义了一个数据属性,该属性具有可写的值、可枚举和可配置的特性。

1.2、用属性描述符定义属性及获取对象的属性描述符

        要使用属性描述符来定义或修改对象属性,可以使用Object.defineProperty()方法,此外,还可以使用Object.getOwnPropertyDescriptor()来获取对象属性的当前属性描述符

let obj = {};

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

// 获取对象属性的当前属性描述符

let propDesc = Object.getOwnPropertyDescriptor(obj, 'myProp');

console.log(propDesc);

// 输出:{ value: 42, writable: true, enumerable: true, configurable: true }

1.3、带有读取器和设置器的属性描述符

        带有读取器(getter)和设置器(setter)的属性描述符允许你定义属性的获取和设置行为,而不是直接存储一个值。这种属性被称为访问器属性。以下是一个带有读取器和设置器的属性描述符的例子:

let obj = {};

// 定义属性描述符,包含读取器和设置器
let descriptor = {
  get: function() {
    // 这个函数会在访问属性时被调用
    console.log('Getting the value!');
    return this._myValue; // 访问器返回内部属性的值
  },
  set: function(newValue) {
    // 这个函数会在设置属性值时被调用
    console.log('Setting the value to ' + newValue);
    this._myValue = newValue; // 设置器将值存储到内部属性
  },
  enumerable: true, // 属性是否可枚举
  configurable: true  // 属性的描述符是否可以被改变
};

// 使用属性描述符定义属性
Object.defineProperty(obj, 'myProperty', descriptor);

// 测试读取器
console.log(obj.myProperty); // 输出: 'Getting the value!' 然后是 undefined

// 测试设置器
obj.myProperty = 10; // 输出: 'Setting the value to 10'
console.log(obj.myProperty); // 输出: 'Getting the value!' 然后是 10

        其中,对obj中myProperty属性进行赋值,就会触发设置器,读取obj的myProperty属性,就会触发读取器。

二、使用属性描述符的情景

2.1、封装和数据隐藏

        使用getter和setter来封装一个对象的内部状态,防止直接访问和修改。
// 使用getter和setter来封装一个对象的内部状态,防止直接访问和修改。

let user = {
  _name: 'Alice',
  get name() {
    return this._name;
  },
  set name(value) {
    if (typeof value === 'string') {
      this._name = value;
    } else {
      console.log('Name must be a string.');
    }
  }
};

console.log(user.name); // Alice
user.name = 'Bob'; // 更新名称
console.log(user.name); // Bob
user.name = 123; // 尝试设置非法名称,将显示错误信息

2.2、 创建只读属性

        通过设置writable为false,可以创建一个不允许修改的属性。
// 通过设置writable为false,可以创建一个不允许修改的属性。

let product = {
  _price: 19.99,
  get price() {
    return this._price;
  }
};

Object.defineProperty(product, 'price', {
  writable: false,
  enumerable: true,
  configurable: true
});

console.log(product.price); // 19.99
// product.price = 24.99; // 这将不会改变价格,因为属性是只读的

 2.3、验证属性赋值

        在setter中添加逻辑来验证属性值,确保它们满足特定条件。
// 在setter中添加逻辑来验证属性值,确保它们满足特定条件。

let account = {
  _balance: 0,
  get balance() {
    return this._balance;
  },
  set balance(amount) {
    if (amount < 0) {
      console.log('Cannot set a negative balance.');
    } else {
      this._balance = amount;
    }
  }
};

account.balance = 1000; // 设置余额
console.log(account.balance); // 1000
account.balance = -500; // 尝试设置负余额,将显示错误信息

三、情景:如果属性描述符中writable为false,但是写了set函数

        如果属性描述符中的 writable 属性设置为 false,这意味着属性的值不能被重新赋值。此时如果尝试通过 set 函数修改属性值,它将不会对属性的实际值产生任何影响,因为 writable 属性已经明确禁止了对值的修改。

let obj = {};

let descriptor = {
  value: 42,
  writable: false, // 禁止修改属性值
  set: function(newValue) {
    console.log(`Attempt to set value to: ${newValue}`);
    // 尽管这里尝试设置新值,但由于 writable: false,这个操作不会有任何效果
    // 甚至连`Attempt to set value to: ${newValue}`都不会打印
    // writable: false情况下,不会触发设置器函数
  },
  enumerable: true,
  configurable: true
};

Object.defineProperty(obj, 'myProperty', descriptor);

console.log(obj.myProperty); // 输出: 42

obj.myProperty = 100; // 尝试修改属性值,但会失败
// "Attempt to set value to: 100" 这一行不会被打印
console.log(obj.myProperty); // 输出仍然是: 42


obj.myProperty = 'new value'; // 再次尝试修改属性值,但仍然会失败
console.log(obj.myProperty); // 输出仍然是: 42

四、总结与相关资源

        属性描述符还有很多内容可以挖掘,比如defineProperty与Proxy的区别,比如vue2与vue3实现数据劫持的方式有什么不同,实现效果有哪些差异等,这篇博文只是入门,以后有时间再深挖。

        博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~

        更多优质内容,请关注:

JS底层逻辑:

        最细最有条理解析:事件循环(消息循环)是什么?进程与线程的定义、关系与差异

        路由通配符,小小的字符有大大的作用,你真的熟悉吗? 

        管理数据必备!侦听器watch用法详解

        什么是深拷贝?深拷贝和浅拷贝有什么区别

JS语法篇:

        你真的会使用Vue3的onMounted钩子函数吗?Vue3中onMounted的用法详解

        对象数据的读取,看这一篇就够了!

        通过array.every()实现数据验证、权限检查和一致性检查,array.some与array.every的区别

        通过array.some()实现权限检查、表单验证、库存管理、内容审查和数据处理

        通过array.map()实现数据转换、创建派生数组、异步数据流处理、搜索和过滤等需求

        通过array.reduce()实现数据汇总、条件筛选和映射、对象属性的扁平化、转换数据格式等

        通过array.filter()实现数组的数据筛选、数据清洗和链式调用

巧妙算法与窍门:

        多维数组操作,不要再用遍历循环foreach了,来试试数组展平的小妙招!

        别再用双层遍历循环来做新旧数组对比,寻找新增元素了!

        shpfile转GeoJSON且控制转化精度;如何获取GeoJSON?GeoJson结构详解

        Mapbox添加行政区矢量图层、分级设色图层、自定义鼠标悬浮框、添加天地图底图等

Element plus拓展:

        通过el-tree自定义渲染网页版工作目录,实现鼠标悬浮显示完整名称等

        el-table实现动态数据的实时排序,一篇文章讲清楚elementui的表格排序功能

        el-table中如何添加渐变色带、多色色带

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

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

相关文章

论文写作全攻略:Kimi辅助下的高效学术写作技巧

学境思源&#xff0c;一键生成论文初稿&#xff1a; AcademicIdeas - 学境思源AI论文写作 完成论文写作是一个多阶段的过程&#xff0c;涉及到不同的任务和技能。以下是按不同分类总结的向Kimi提问的prompt&#xff0c;以帮助你在论文写作过程中取得成功&#xff1a; 1. 选题与…

使用kali Linux启动盘轻松破解Windows电脑密码

破解分析文章仅限用于学习和研究目的&#xff1b;不得将上述内容用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。谢谢&#xff01;&#xff01; 效果展示&#xff1a; 使用kali Linux可以轻松破解Windows用户及密码 准备阶段&#xff1a; &#xff08…

RedHat9 | kickstart无人值守批量安装

一、知识补充 kickstart Kickstart是一种用于Linux系统安装的自动化工具&#xff0c;它通过一个名为ks.cfg的配置文件来定义Linux安装过程中的各种参数和设置。 kickstart的工作原理 Kickstart的工作原理是通过记录典型的安装过程中所需人工干预填写的各种参数&#xff0c;…

配置基于用户认证的虚拟主机

添加账号abc [rootlocalhost conf.d]# htpasswd -c /etc/httpd/zhanghao abc New password: Re-type new password: Adding password for user abc添加账号tom [rootlocalhost conf.d]# htpasswd /etc/httpd/zhanghao tom New password: Re-type new password: Adding pa…

QT中QDomDocument读写XML文件

一、XML文件 <?xml version"1.0" encoding"UTF-8"?> <Begin><Type name"zhangsan"><sex>boy</sex><school>Chengdu</school><age>18</age><special>handsome</special>&l…

平安养老险蚌埠中心支公司开展“78奋力前行”健步走活动

7月4日&#xff0c;平安养老保险股份有限公司&#xff08;以下简称“平安养老险”&#xff09;蚌埠中心支公司组织员工在张公山公园开展“78奋力前行”健步走活动&#xff0c;传递保险行业的正能量&#xff0c;展现平安养老险的活力与风采。 平安养老险蚌埠中心支公司员工身着…

【瑞吉外卖 | day02】登录功能完善+员工信息的增改查

文章目录 瑞吉外卖 — day021. 完善登录功能1.1 问题分析1.2 实现 2. 新增员工功能2.1 分析2.2 程序执行过程2.3 程序执行中的异常处理 3. 员工信息分页查询3.1 程序执行过程 4. 启用/禁用员工账号4.1 需求分析4.2 程序执行过程4.3 代码修复 5. 编辑员工信息5.1 需求分析5.2 程…

基于DMAIC降低气缸体水套芯磕碰伤率

在制造业的激烈竞争中&#xff0c;产品质量的提升一直是企业追求的目标。气缸体作为汽车发动机的核心部件&#xff0c;其生产过程中的质量控制尤为重要。今天&#xff0c;深圳天行健企业管理咨询公司就来分享一下如何运用DMAIC&#xff08;定义、测量、分析、改进、控制&#x…

Logstash安装插件失败的问题

Logstash安装插件失败的问题 安装 logstash-output-jdbc 失败 报错为&#xff1a; Unable to download data from https://rubygems.org - Net::OpenTimeout: Failed to open TCP connection to rubygems.org:443 (execution expired) (https://rubygems.org/latest_specs.4.…

[GHCTF 2024 新生赛]UP+——入土为安的第一天

注意&#xff1a;这道题需要脱壳&#xff0c;而且需要改特征值&#xff0c;详细请看 [LitCTF 2024]hello_upx——入土为安的第一天-CSDN博客 脱完壳发现有256这个特殊的数&#xff0c;是rc4类型的题&#xff0c;最后有一个异或 a "9F041CEFA92386B6F56F27B96155FD42&qu…

鸿蒙应用开发之Column容器

这个容器已经使用了很多次,但是还是需要来简单地学习一下,它的主要作用是沿垂直方向布局的容器。 对于布局这种容器,需要看到显示的效果才会比较明白。 先来看下面这个界面: 先在最外面建立一个Column容器,space和方框显示等显示内容都是作为一行进行排列。现在这里设置为…

智能升级,监控无界——全新安全生产生态算法一体机上线

安全生产生态算法一体机 安全生产生态算法一体机是万物纵横推出的一款AI算法软硬一体生态产品&#xff0c;重点面向安全生产领域&#xff0c;采用BM1684强劲AI芯片&#xff0c;内置安全生产场景所需的多种专用AI算法&#xff0c;面向各场景的人员监控、规范作业、异常检测等应…

maven项目启动的时候,自动启动netty

1.写一个监听器,重开一个线程初始化,netty,一定要重开一个线程去启动,要不会阻塞的 public class StartupListener implements ServletContextListener {Overridepublic void contextInitialized(ServletContextEvent sce) {// 在Web应用启动时启动WebSocket服务器new Thread(…

2024 MWC上海:Infobip引领CPaaS新纪元

作为全球通信行业一年一度的顶级盛会&#xff0c;MWC上海2024于近日在上海盛大召开。Infobip以其前瞻性的CPaaS&#xff08;Communication Platform as a Service&#xff0c;通信平台即服务&#xff09;解决方案和广泛的合作伙伴网络&#xff0c;成为了众多参展嘉宾瞩目的焦点…

Leetcode.342 4的幂

给定一个整数&#xff0c;写一个函数来判断它是否是 4 的幂次方。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 整数 n 是 4 的幂次方需满足&#xff1a;存在整数 x 使得 n 4x 示例 1&#xff1a; 输入&#xff1a;n 16 输出&#xff1a;true示…

QT的编译过程(底层逻辑)

qmake -project 用于从源代码生成项目文件&#xff0c;qmake 用于从项目文件生成 Makefile&#xff0c;而 make 用于根据 Makefile 构建项目。 详细解释&#xff1a; qmake -project 这个命令用于从源代码目录生成一个初始的 Qt 项目文件&#xff08;.pro 文件&#xff09;。它…

通过营销本地化解锁全球市场

在一个日益互联的世界里&#xff0c;企业必须接触到全球各地的不同受众。营销本地化是打开这些全球市场的关键。它包括调整营销材料&#xff0c;使其与不同地区的文化和语言细微差别产生共鸣。以下是有效的营销本地化如何推动您的全球扩张&#xff0c;并用实际例子来说明每一点…

在PyTorch中使用TensorBoard

文章目录 在PyTorch中使用TensorBoard1.安装2.TensorBoard使用2.1创建SummaryWriter实例2.2利用add_scalar()记录metrics2.3关闭Writer2.4启动TensorBoard 3.本地连接服务器使用TensorBoard3.1方法一&#xff1a;使用SSH命令进行本地端口转发3.2方法二&#xff1a;启动TensorBo…

昇思25天学习打卡营第12天|ResNet50迁移学习

昇思25天学习打卡营第12天|ResNet50迁移学习 前言ResNet50迁移学习数据准备下载数据集 加载数据集数据集可视化 训练模型构建Resnet50网络固定特征进行训练训练和评估可视化模型预测 个人任务打卡&#xff08;读者请忽略&#xff09;个人理解与总结 前言 非常感谢华为昇思大模型…

File类常用构造方法及方法详解

File类是对文件或者目录的一系列操作。如文件和目录的创建、检查、删除、路径获取等。现介绍下常用构造方法和方法。 一、构造方法。 File类提供了多个构造方法来创建File对象&#xff0c;以表示文件或目录。 1. File(String pathname) 通过指定文件路径名创建File对象。 参…