Object.defineProperty() 完整指南

Object.defineProperty() 完整指南

1. 基本概念

Object.defineProperty() 方法允许精确地添加或修改对象的属性。默认情况下,使用此方法添加的属性是不可修改的。

1.1 基本语法

Object.defineProperty(obj, prop, descriptor)

参数说明:

  • obj: 要定义属性的对象
  • prop: 要定义或修改的属性名
  • descriptor: 属性描述符对象

2. 属性描述符

2.1 数据描述符

const obj = {};Object.defineProperty(obj, 'name', {value: 'John',          // 属性值writable: true,         // 是否可写enumerable: true,       // 是否可枚举configurable: true      // 是否可配置
});

2.2 访问器描述符

const obj = {_name: 'John'
};Object.defineProperty(obj, 'name', {get() {return this._name;},set(value) {this._name = value;},enumerable: true,configurable: true
});

3. 实际应用示例

3.1 数据劫持(Vue2响应式原理)

function observe(obj) {if (typeof obj !== 'object' || obj === null) {return;}Object.keys(obj).forEach(key => {defineReactive(obj, key, obj[key]);});
}function defineReactive(obj, key, val) {// 递归处理嵌套对象observe(val);Object.defineProperty(obj, key, {get() {console.log(`获取${key}属性`);return val;},set(newVal) {if (val === newVal) return;console.log(`设置${key}属性为${newVal}`);val = newVal;// 触发更新}});
}// 使用示例
const data = {name: 'John',age: 20
};observe(data);
data.name = 'Mike'; // 设置name属性为Mike
console.log(data.name); // 获取name属性 Mike

3.2 私有属性模拟

function Person(name) {let _name = name;Object.defineProperty(this, 'name', {get() {return _name;},set(value) {if (typeof value !== 'string') {throw new Error('Name must be a string');}_name = value;}});
}const person = new Person('John');
console.log(person.name); // John
person.name = 'Mike'; // 正常设置
person.name = 123; // 抛出错误

3.3 计算属性实现

function computed(obj, key, computeFunc) {let value = computeFunc();Object.defineProperty(obj, key, {get() {return value;},set() {console.warn(`${key} is a computed property, cannot be modified`);}});
}const obj = {a: 1,b: 2
};computed(obj, 'sum', () => obj.a + obj.b);
console.log(obj.sum); // 3
obj.sum = 10; // 警告:sum is a computed property, cannot be modified

4. 注意事项和限制

4.1 不可扩展对象

const obj = {};
Object.preventExtensions(obj);// 这将抛出错误
Object.defineProperty(obj, 'name', {value: 'John'
});

4.2 继承属性

const parent = {};
Object.defineProperty(parent, 'name', {value: 'John',writable: false
});const child = Object.create(parent);
// 这将抛出错误
child.name = 'Mike';

4.3 属性描述符限制

const obj = {};// 不能同时指定 value/writable 和 get/set
Object.defineProperty(obj, 'name', {value: 'John',get() {return 'John';}
}); // 抛出错误

5. 性能考虑

5.1 大量属性处理

// 不推荐
const obj = {};
for (let i = 0; i < 1000; i++) {Object.defineProperty(obj, `prop${i}`, {value: i,writable: true});
}// 推荐
const descriptors = {};
for (let i = 0; i < 1000; i++) {descriptors[`prop${i}`] = {value: i,writable: true,configurable: true,enumerable: true};
}
Object.defineProperties(obj, descriptors);

5.2 访问器性能

// 避免在访问器中进行复杂计算
Object.defineProperty(obj, 'name', {get() {// 不推荐return complexCalculation();}
});// 推荐:缓存计算结果
let cachedValue;
Object.defineProperty(obj, 'name', {get() {if (cachedValue === undefined) {cachedValue = complexCalculation();}return cachedValue;}
});

6. 最佳实践

  1. 描述符默认值
// 记住默认值都是 false
Object.defineProperty(obj, 'name', {value: 'John'// writable: false// enumerable: false// configurable: false
});
  1. 使用 TypeScript 类型
interface PropertyDescriptor {configurable?: boolean;enumerable?: boolean;value?: any;writable?: boolean;get?(): any;set?(v: any): void;
}
  1. 错误处理
function safeDefineProperty(obj, prop, descriptor) {try {Object.defineProperty(obj, prop, descriptor);return true;} catch (error) {console.error(`Failed to define property ${prop}:`, error);return false;}
}

7. 总结

Object.defineProperty() 的关键点:

  1. 使用场景

    • 数据劫持
    • 私有属性模拟
    • 计算属性实现
    • 属性访问控制
  2. 注意事项

    • 描述符类型限制
    • 性能考虑
    • 继承关系处理
    • 错误处理
  3. 最佳实践

    • 合理使用缓存
    • 避免复杂计算
    • 注意默认值
    • 做好错误处理

10. 深入理解 Object.defineProperty()

10.1 基础概念详解

Object.defineProperty() 是 JavaScript 中用于在对象上定义新属性或修改现有属性的方法。它允许精确控制属性的特性。

// 基本语法
Object.defineProperty(obj, prop, descriptor)// 参数说明
// obj: 要定义属性的对象
// prop: 要定义或修改的属性名
// descriptor: 属性描述符对象

10.2 属性描述符详解

属性描述符分为两种类型:数据描述符和访问器描述符。

  1. 数据描述符的完整选项:
const obj = {};
Object.defineProperty(obj, 'name', {value: 'John',          // 属性值writable: true,         // 是否可写enumerable: true,       // 是否可枚举configurable: true      // 是否可配置
});
  1. 访问器描述符的完整选项:
const obj = {_name: 'John'
};
Object.defineProperty(obj, 'name', {get() {console.log('Getting value');return this._name;},set(value) {console.log('Setting value to', value);this._name = value;},enumerable: true,configurable: true
});

10.3 常见使用场景

  1. 只读属性:
const obj = {};
Object.defineProperty(obj, 'readonly', {value: 'I am read-only',writable: false,enumerable: true,configurable: false
});obj.readonly = 'New value'; // 无效
console.log(obj.readonly);  // 'I am read-only'
  1. 不可枚举属性:
const obj = {};
Object.defineProperty(obj, 'hidden', {value: 'You cannot see me',enumerable: false
});console.log(Object.keys(obj)); // []
console.log(obj.hidden);       // 'You cannot see me'
  1. 计算属性:
const person = {firstName: 'John',lastName: 'Doe'
};Object.defineProperty(person, 'fullName', {get() {return `${this.firstName} ${this.lastName}`;},set(value) {[this.firstName, this.lastName] = value.split(' ');}
});console.log(person.fullName);    // 'John Doe'
person.fullName = 'Jane Smith';
console.log(person.firstName);   // 'Jane'
console.log(person.lastName);    // 'Smith'
  1. Vue 双向绑定实现:
function observe(obj) {if (!obj || typeof obj !== 'object') return;// 遍历对象的每个属性Object.keys(obj).forEach(key => {let value = obj[key];let dep = new Dep(); // 依赖收集器Object.defineProperty(obj, key, {get() {// 收集依赖if (Dep.target) {dep.addDep(Dep.target);}return value;},set(newValue) {if (value === newValue) return;value = newValue;// 通知所有依赖进行更新dep.notify();}});// 递归观察子属性if (typeof value === 'object') {observe(value);}});
}// 使用示例
const data = {user: {name: 'John',age: 20}
};observe(data);
// 现在 data 对象的所有属性都是响应式的

10.4 注意事项和最佳实践

  1. 描述符限制:
// 不能同时使用数据描述符和访问器描述符
Object.defineProperty(obj, 'prop', {value: 123,get() { return 123; } // 错误!
});
  1. 性能优化:
// 批量定义属性
Object.defineProperties(obj, {prop1: {value: 123,writable: true},prop2: {get() { return this.prop1 * 2; }}
});
  1. 默认值处理:
// 所有描述符属性默认为 false
Object.defineProperty(obj, 'prop', {value: 123// writable: false// enumerable: false// configurable: false
});

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【pytorch】conda安装pytorch

Step 1 打开官网&#xff1a; https://pytorch.org/get-started/locally/ 进行选择对应版本&#xff1a; 复制图中命令执行。 Step 2 验证是否安装成功。 执行&#xff1a; import torch print(torch.cuda.is_available()) print(torch.cuda.device_count()) print(torch.…

项目开发实践——基于SpringBoot+Vue3实现的在线考试系统(四)

文章目录 一、管理员角色功能实现1、添加教师功能实现1.1 页面设计1.2 前端功能实现1.3 后端功能实现1.4 效果展示2、教师管理功能实现2.1 页面设计2.2 前端功能实现2.3 后端功能实现2.3.1 后端查询接口实现2.3.2 后端编辑接口实现2.3.3 后端删除接口实现2.4 效果展示二、代码下…

基于16QAM的载波同步和定时同步性能仿真,采用四倍采样,包括Costas环和gardner环

目录 1.算法仿真效果 2.算法涉及理论知识概要 3.MATLAB核心程序 4.完整算法代码文件获得 1.算法仿真效果 matlab2022a仿真结果如下&#xff08;完整代码运行后无水印&#xff09;&#xff1a; 仿真操作步骤可参考程序配套的操作视频。 2.算法涉及理论知识概要 载波同步是…

新服务器ubuntu系统相关操作

1、查看驱动:驱动版本535.216.01能够支持cuda12.2,下面直接使用默认安装的cuda。 2、赋予用户管理员权限。 首先有超级用户(root)权限来编辑 /etc/sudoers 文件,visudo 是一个命令,用于安全地编辑 /etc/sudoers 文件。运行: sudo visudo 在 visudo 编辑器中,找到类似…

2、Bert论文笔记

Bert论文 1、解决的问题2、预训练微调2.1预训练微调概念2.2深度双向2.3基于特征和微调&#xff08;预训练下游策略&#xff09; 3、模型架构4、输入/输出1.输入&#xff1a;2.输出&#xff1a;3.Learned Embeddings(学习嵌入)1. **Token Embedding**2. **Position Embedding**3…

python 渗透开发工具之SQLMapApi Server不同IP服务启动方式处理 解决方案SqlMapApiServer外网不能访问的情况

目录 说在前面 什么是 SQLMapAPI 说明 sqlmapApi能干什么 sqlmapApi 服务安装相关 kali-sqlmap存放位置 正常启动sqlmap-api server SqlMapApi-Server 解决外网不能访问情况 说在前面 什么是sqlmap 这个在前面已经说过了&#xff0c;如果这个不知道&#xff0c;就可以…

操作系统论文导读(八):Schedulability analysis of sporadic tasks with multiple criticality specifications——具有多个

Schedulability analysis of sporadic tasks with multiple criticality specifications——具有多个关键性规范的零星任务的可调度性分析 目录 一、论文核心思想 二、基本定义 2.1 关键性指标 2.2 任务及相关参数定义 2.3 几个基础定义 三、可调度性分析 3.1 调度算法分…

技术速递|调用异步功能 - WinForms 在 .NET 9 中的未来发展

作者&#xff1a; Klaus Loeffelmann 排版&#xff1a;Alan Wang 随着 .NET 的不断发展&#xff0c;WinForms 开发者可用的工具也在不断进步&#xff0c;这使得开发更加高效且应用响应更迅速。在 .NET 9 中&#xff0c;我们很高兴引入了一系列新的异步 API&#xff0c;这些 API…

Docker-构建自己的Web-Linux系统-镜像webtop:ubuntu-kde

介绍 安装自己的linux-server,可以作为学习使用&#xff0c;web方式访问&#xff0c;基于ubuntu构建开源项目 https://github.com/linuxserver/docker-webtop安装 docker run -d -p 1336:3000 -e PASSWORD123456 --name webtop lscr.io/linuxserver/webtop:ubuntu-kde登录 …

【每日学点鸿蒙知识】箭头函数、Watch状态变量、H5获取定位数据、前后台切换、长按事件

【每日学点鸿蒙知识】箭头函数、Watch状态变量、H5获取定位数据、前后台切换、长按事件 1、HarmonyOS confirm: () > void () > { }&#xff1f; confirm: () > void () > { }是什么格式。 是一个箭头函数&#xff0c;它的类型是 () > void&#xff0c;表示…

【人工智能机器学习基础篇】——深入详解监督学习之模型评估:掌握评估指标(准确率、精确率、召回率、F1分数等)和交叉验证技术

深入详解监督学习之模型评估 在监督学习中&#xff0c;模型评估是衡量模型性能的关键步骤。有效的模型评估不仅能帮助我们理解模型在训练数据上的表现&#xff0c;更重要的是评估其在未见数据上的泛化能力。本文将深入探讨监督学习中的模型评估方法&#xff0c;重点介绍评估指…

如何使用React,透传各类组件能力/属性?

在23年的时候&#xff0c;我主要使用的框架还是Vue&#xff0c;当时写了一篇“如何二次封装一个Vue3组件库&#xff1f;”的文章&#xff0c;里面涉及了一些如何使用Vue透传组件能力的方法。在我24年接触React之后&#xff0c;我发现这种扩展组件能力的方式有一个专门的术语&am…

点进CSS选择器

CSS 1.直接在标签的style属性进行设置(行内式) //写在数据单元格td标签内的stytle&#xff0c;设置color颜色和font-size字体大小&#xff1b; <td rowspan"3" style"color: red;font-size: 12px;">Web技术与应用</td> 2.写在head标签中的…

Python基于卷积神经网络的车牌识别系统开发与实现

1. 简介 车牌识别是人工智能在交通领域的重要应用&#xff0c;广泛用于高速违章检测、停车场管理和智能交通系统等场景。本系统通过基于卷积神经网络&#xff08;CNN&#xff09;的深度学习算法&#xff0c;结合 Python 和 MySQL 实现车牌的快速识别与管理。 系统特点&#x…

【PDF物流单据提取明细】批量PDF提取多个区域内容导出表格或用区域内容对文件改名,批量提取PDF物流单据单号及明细导出表格并改名的技术难点及小节

相关阅读及下载&#xff1a; PDF电子物流单据&#xff1a; 批量PDF提取多个区域局部内容重命名PDF或者将PDF多个局部内容导出表格&#xff0c;具体使用步骤教程和实际应用场景的说明演示https://mp.weixin.qq.com/s/uCvqHAzKglfr40YPO_SyNg?token720634989&langzh_CN扫描…

运行python程序报错 undefined symbol: ffi_type_uint32 的参考解决方法

文章目录 写在前面一、问题描述二、解决方法参考链接 写在前面 自己的测试环境&#xff1a; Ubuntu20.04 ROS-Noetic 一、问题描述 运行 python 程序出现如下问题&#xff1a; Traceback (most recent call last):File "<string>", line 1, in <module&…

鱼眼相机模型与去畸变实现

1.坐标系说明 鱼眼相机模型涉及到世界坐标系、相机坐标系、图像坐标系、像素坐标系之间的转换关系。对于分析鱼眼相机模型&#xff0c;假定世界坐标系下的坐标点,经过外参矩阵的变换转到相机坐标系&#xff0c;相机坐标再经过内参转换到像素坐标&#xff0c;具体如下 进一步进…

ASP.NET Core Web API Hangfire

ASP.NET Core Web API Hangfire 前言一、安装二、相关代码1.代码片段2.代码片段3.运行效果 三、测试代码1.即发即弃作业2.延迟作业3.重复作业4.延续作业5.页面调度作业 前言 &#x1f468;‍&#x1f4bb;&#x1f468;‍&#x1f33e;&#x1f4dd;记录学习成果&#xff0c;以…

DevOps实战:用Kubernetes和Argo打造自动化CI/CD流程(1)

DevOps实战&#xff1a;用Kubernetes和Argo打造自动化CI/CD流程&#xff08;1&#xff09; 架构 架构图 本设计方案的目标是在一台阿里云ECS服务器上搭建一个轻量级的Kubernetes服务k3s节点&#xff0c;并基于Argo搭建一套完整的DevOps CI/CD服务平台&#xff0c;包括Argo CD…

【openGauss】正则表达式次数符号“{}“在ORACLE和openGauss中的差异

一、前言 正则作为一种常用的字符串处理方式&#xff0c;在各种开发语言&#xff0c;甚至数据库中&#xff0c;都有自带的正则函数。但是正则函数有很多标准&#xff0c;不同标准对正则表达式的解析方式不一样&#xff0c;本次在迁移一个ORACLE数据库到openGauss时发现了一个关…