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

JavaScript中Object.defineProperty的作用和用法以及和proxy的区别

在 JavaScript 中,Object.defineProperty() 是一个强大的内置方法,用于精确控制对象属性的配置。它允许你直接修改对象属性的底层特性(如可读写性、可枚举性、可配置性),甚至可以自定义属性的 getter 和 setter 方法。

核心作用

  1. 精确控制属性配置
    通过设置属性描述符(descriptor),可以精确控制属性的行为。
  2. 实现数据劫持
    通过 getter/setter 拦截属性的读取和赋值操作,常用于响应式系统(如 Vue.js 的数据绑定)。
  3. 阻止属性被意外修改
    通过设置 writable: falseconfigurable: false 保护属性不被修改或删除。

基本语法

Object.defineProperty(obj, prop, descriptor);
  • obj:需要定义属性的对象。
  • prop:需要定义或修改的属性名称(字符串或 Symbol)。
  • descriptor:属性描述符对象,包含以下可选键:
    • value:属性的值(默认 undefined)。
    • writable:属性值是否可修改(默认 false)。
    • enumerable:属性是否可被枚举(如 for...in 循环,默认 false)。
    • configurable:属性是否可被删除或重新配置(默认 false)。
    • get:获取属性值的函数(与 value 互斥)。
    • set:设置属性值的函数(与 value 互斥)。

用法示例

1. 基本属性定义
const person = {};Object.defineProperty(person, 'name', {value: 'John',writable: true,     // 允许修改值enumerable: true,   // 可被枚举configurable: true  // 可被重新配置或删除
});console.log(person.name); // "John"
person.name = 'Jane';     // 修改有效(writable: true)
console.log(person.name); // "Jane"
2. 只读属性(writable: false
const person = {};Object.defineProperty(person, 'age', {value: 30,writable: false,    // 只读enumerable: true
});console.log(person.age); // 30
person.age = 31;         // 赋值无效(严格模式下会报错)
console.log(person.age); // 30
3. 不可枚举属性(enumerable: false
const person = { name: 'John' };Object.defineProperty(person, 'age', {value: 30,enumerable: false   // 不可枚举
});console.log(person.age); // 30
for (const key in person) {console.log(key); // 仅输出 "name"(age 不可枚举)
}
4. 不可配置属性(configurable: false
const person = {};Object.defineProperty(person, 'name', {value: 'John',configurable: false  // 不可重新配置或删除
});delete person.name;    // 删除无效
console.log(person.name); // "John"// 尝试重新配置会报错(严格模式下)
Object.defineProperty(person, 'name', {value: 'Jane'
}); // TypeError: Cannot redefine property: name
5. 数据劫持(getter/setter)
const person = {_age: 30 // 约定使用下划线表示私有属性
};Object.defineProperty(person, 'age', {get() {console.log('读取 age');return this._age;},set(newValue) {console.log('设置 age 为', newValue);if (newValue < 0) throw new Error('年龄不能为负数');this._age = newValue;}
});console.log(person.age); // 读取 age → 30
person.age = 31;         // 设置 age 为 31
person.age = -5;         // Error: 年龄不能为负数

应用场景

  1. 实现响应式系统
    Vue.js 2.x 利用 Object.defineProperty() 实现数据劫持,当属性值变化时自动更新 DOM:

    function defineReactive(obj, key, value) {Object.defineProperty(obj, key, {get() {// 依赖收集return value;},set(newValue) {if (value !== newValue) {value = newValue;// 触发更新updateDOM();}}});
    }
    
  2. 实现私有属性
    通过 getter/setter 控制属性访问权限:

    const person = {};
    let _age = 30; // 闭包中的私有变量Object.defineProperty(person, 'age', {get() { return _age; },set(value) { _age = value; }
    });
    
  3. 阻止对象被篡改
    通过设置 configurable: falsewritable: false 保护关键属性:

    const config = { API_KEY: 'secret' };Object.defineProperty(config, 'API_KEY', {writable: false,configurable: false
    });// 无法修改或删除 API_KEY
    

注意事项

  1. 兼容性Object.defineProperty() 是 ES5 引入的方法,不支持 IE8 及以下版本。
  2. 性能影响:频繁触发 getter/setter 会有一定性能开销,避免在高性能场景(如大型循环)中过度使用。
  3. 深度监听Object.defineProperty() 只能监听对象的直接属性,若要监听嵌套对象,需要递归处理。
  4. 数组监听限制:直接监听数组变化存在局限性(Vue.js 3 改用 Proxy 解决此问题)。

Proxy 的对比

特性Object.defineProperty()Proxy
监听范围只能监听对象的已有属性(需逐个定义)可以监听整个对象(包括新增属性)
数组支持对数组的监听有限(需特殊处理)全面支持数组操作
元编程能力仅能控制单个属性可以拦截多种操作(如 indelete
兼容性ES5(支持 IE9+)ES6(不支持 IE)

Object.defineProperty() 是 JavaScript 中强大的元编程工具,适合需要精确控制对象属性行为的场景,尤其在实现响应式系统、数据验证和属性保护等方面有广泛应用。

http://www.xdnf.cn/news/1123507.html

相关文章:

  • SSM框架学习——day1
  • Datawhale AI夏令营-基于带货视频评论的用户洞察挑战赛
  • AI Linux 运维笔记
  • Imx6ull用网线与电脑连接
  • 使用 pytest 测试框架构建自动化测试套件之一
  • ethers.js-5–和solidity的关系
  • pytorch学习1(DataSet+Transforms+TensorBoard)
  • LeetCode 692题解 | 前K个高频单词
  • 工业软件加密锁复制:一场技术与安全的博弈
  • Lovable - AI 驱动的全栈应用开发平台
  • PyTorch张量(Tensor)创建的方式汇总详解和代码示例
  • [笔记] 动态 SQL 查询技术解析:构建灵活高效的企业级数据访问层
  • Linux:1_Linux下基本指令
  • TCP心跳机制详解
  • 使用axios向服务器请求信息并渲染页面
  • 如何在服务器上运行一个github项目
  • K8S的平台核心架构思想[面向抽象编程]
  • docker私有仓库
  • Ai问答之空间站星等
  • 【科研绘图系列】R语言绘制世界地图
  • C++ 中常见的字符串定义方式及其用法
  • 使用Java完成下面项目
  • 解决chrome v2 版本插件不支持
  • uni-app在安卓设备上获取 (WIFI 【和】以太网) ip 和 MAC
  • C语言-数据输入与输出
  • java学习 day4 分布式锁
  • 【Learning Notes】 Derak Callan‘s Business English P38~40
  • 【【异世界历险之数据结构世界(二叉树)】】
  • Why C# and .NET are still relevant in 2025
  • 安装Keycloak并启动服务(macOS)