当前位置: 首页 > news >正文

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
});

相关文章:

Object.defineProperty() 完整指南

Object.defineProperty() 完整指南 1. 基本概念 Object.defineProperty() 方法允许精确地添加或修改对象的属性。默认情况下&#xff0c;使用此方法添加的属性是不可修改的。 1.1 基本语法 Object.defineProperty(obj, prop, descriptor)参数说明&#xff1a; obj: 要定义…...

postgresql函数创建

postgresql的函数创建 1.创建函数的基本语法&#xff1a; CREATE [OR REPLACE] FUNCTION function_name(parameter_list) RETURNS return_type AS $$ BEGIN -- 函数体 END; $$ LANGUAGE language_name;2.创建函数时传入参数示例:add_user tbl_user表 | id | username | …...

ECMAScript 变量

文章目录 前言一、ECMAScript 变量二、var 关键字1、var 声明作用域2、var 声明提升(hoist)三、let 关键字四、const 关键字🔰 总结前言 任何语言的核心所描述的都是这门语言在最基本的层面上如何工作,涉及 语法、操作符、数据类型以及内置功能,在此基础之上才可以构建复…...

CAN总线波形中最后一位电平偏高或ACK电平偏高问题分析

参考&#xff1a;https://zhuanlan.zhihu.com/p/689336144 有时候看到CAN总线H和L的差值波形的最后一位电平会变高很多&#xff0c;这是什么原因呢&#xff1f; 实际上这是正常的现象&#xff0c;最后一位是ACK位。问题描述为&#xff1a;CAN总线ACK电平偏高。 下面分析下原因…...

【C++】22___STL常用算法

目录 一、常用遍历算法 二、常用查找算法 2.1 find 2.2 其它查找算法 三、常用排序算法 3.1 sort 3.2 其它排序算法 四、拷贝 & 替换 4.1 copy 4.2 其它算法 五、常用的算数生成算法 5.1 accumulate 5.2 fill 六、常用集合算法 6.1 set_intersection 6…...

意静明和-十成

十成 责任&#xff08;健康&#xff09;、使命&#xff08;事业&#xff09;、信念&#xff08;意义&#xff09;、自律&#xff08;排诱&#xff09;、自修&#xff08;知识&#xff09;、总结&#xff08;四为&#xff09;、执行&#xff08;一事不拖&#xff09;、人情&…...

easyui textbox使用placeholder无效

easyui textbox使用placeholder无效 在easyui 的textbox控件&#xff0c;请使用data-options 设定 示例 <input type text class easyui-textbox data-options "prompt:请输入您的邮箱"/>...

flux中的缓存

1. cache&#xff0c;onBackpressureBuffer。都是缓存。cache可以将hot流的数据缓存起来。onBackpressureBuffer也是缓存&#xff0c;但是当下游消费者的处理速度比上游生产者慢时&#xff0c;上游生产的数据会被暂时存储在缓冲区中&#xff0c;防止丢失。 2. Flux.range 默认…...

代码重定位详解

文章目录 一、段的概念以及重定位的引入1.1 问题的引入1.2 段的概念1.3 重定位 二、如何实现重定位2.1 程序中含有什么&#xff1f;2.2 谁来做重定位&#xff1f;2.3 怎么做重定位和清除BSS段&#xff1f;2.4 加载地址和链接地址的区别 三、散列文件使用与分析3.1 重定位的实质…...

活动预告 | Microsoft 365 在线技术公开课:让组织针对 Microsoft Copilot 做好准备

课程介绍 通过Microsoft Learn免费参加Microsoft 365在线技术公开课&#xff0c;建立您需要的技能&#xff0c;以创造新的机会并加速您对Microsoft云技术的理解。参加我们举办的“让组织针对 Microsoft Copilot for Microsoft 365 做好准备” 在线技术公开课活动&#xff0c;学…...

从0到机器视觉工程师(一):机器视觉工业相机总结

目录 相机的作用 工业相机 工业相机的优点 工业相机的种类 工业相机知名品牌 光源与打光 打光方式 亮暗场照明 亮暗场照明的应用 亮暗场照明的区别 前向光漫射照明 背光照明 背光照明的原理 背光照明的应用 同轴光照明 同轴光照明的应用 总结 相机的作用 相机…...

Docker安装(Docker Engine安装)

一、Docker Engine和Desktop区别 Docker Engine 核心组件&#xff1a;Docker Engine是Docker的核心运行时引擎&#xff0c;负责构建、运行和管理容器。它包括守护进程&#xff08;dockerd&#xff09;、API和命令行工具客户端&#xff08;docker&#xff09;。适用环境&#…...

数组的深度监听deep

场景&#xff1a;组件提供的emit事件可能被占用&#xff0c;在不能使用事件提交的情况下&#xff0c;就要上watch数组监听了&#xff0c;但是是发现只有在数组的长度发生变化的时候才会触发监听&#xff0c;这怎么行。。。。。 对于对象数组的深度监听&#xff0c;如果没有正确…...

点击锁定按钮,锁定按钮要变成解锁按钮,然后状态要从待绑定变成 已锁定(升级版)

文章目录 1、updateInviteCodeStatus2、handleLock3、InviteCodeController4、InviteCodeService5、CrudRepository 点击锁定按钮&#xff0c;锁定按钮要变成解锁按钮&#xff0c;然后状态要从待绑定变成 已锁定&#xff1a;https://blog.csdn.net/m0_65152767/article/details…...

UniApp 性能优化策略

一、引言 在当今数字化时代&#xff0c;移动应用的性能成为影响用户留存与满意度的关键因素。UniApp 作为一款热门的跨平台开发框架&#xff0c;以一套代码适配多端的特性极大提升了开发效率&#xff0c;但同时也面临着性能优化的挑战。优化 UniApp 性能&#xff0c;不仅能够让…...

【Linux报告】实训六 重置超级用户密码

实训六 重置超级用户密码 2018编写-今日公布 【练习一】忘记root密码 步骤一&#xff1a;开启或重启系统&#xff0c;并且要在五秒之内按任何键&#xff1b; 步骤二&#xff1a;按任意键&#xff0c;停止进入系统&#xff0c;按【e】键&#xff0c;跳转新页面&#xff0c;再…...

smolagents:一个用于构建代理的简单库

HF推出 smolagents&#xff0c;一个非常简单的库&#xff0c;它能够解锁语言模型的代理功能。以下是它的简要介绍&#xff1a; from smolagents import CodeAgent, DuckDuckGoSearchTool, HfApiModelagent CodeAgent(tools[DuckDuckGoSearchTool()], modelHfApiModel())agent…...

通过Dockerfile来实现项目可以指定读取不同环境的yml包

通过Dockerfile来实现项目可以指定读取不同环境的yml包 1. 挂载目录2. DockerFile3. 运行脚本deploy.sh4. 运行查看日志进入容器 5. 接口测试修改application-dev.yml 6. 优化Dockerfile7. 部分参数解释8. 优化不同环境下的日志也不同调整 Dockerfile修改部署脚本 deploy.sh重新…...

云手机 —— 手机矩阵的 “超级外挂

如何打造手机矩阵 打造手机矩阵主要包括以下几个步骤: 1.确定目标与需求:首先&#xff0c;明确打造手机矩阵的目的和需求&#xff0c;是为了进行电商运营、自媒体推广、任务管理还是其他目的。这将决定后续的手机数量、操作系统选择以及应用安装等。 2.选择手机与操作系统:根据…...

OpenCV的TickMeter计时类

OpenCV的TickMeter计时类 1. TickMeter是一个计时的类1.1 计算耗时1.2 计算循环的平均耗时和FPS1.3 function 2. 案例 1. TickMeter是一个计时的类 https://docs.opencv.org/4.x/d9/d6f/classcv_1_1TickMeter.html#details 1.1 计算耗时 TickMeter tm;tm.start();// do some…...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型&#xff1a;架构设计与关键步骤 在当今数字化转型的浪潮中&#xff0c;大语言模型&#xff08;LLM&#xff09;已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中&#xff0c;不仅可以优化用户体验&#xff0c;还能为业务决策提供…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录

ASP.NET Core 是一个跨平台的开源框架&#xff0c;用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录&#xff0c;以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

设计模式和设计原则回顾

设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...