JavaScript属性描述符详解

在 JavaScript 中,属性描述符(Property Descriptor) 是一个用于定义或修改对象属性特性的对象。它控制属性的行为,例如是否可写、可枚举、可配置等。属性描述符分为两种类型:数据描述符 和 存取描述符。

1. 核心概念

属性描述符的键值:

键名 数据类型 作用 默认值
value any 属性的值(仅用于数据描述符) undefined
writable boolean 属性值是否可修改(仅用于数据描述符) false
enumerable boolean 属性是否出现在对象的枚举属性中(如 for…in、Object.keys()) false
configurable boolean 属性描述符是否可修改,属性是否可删除 false
get function 属性的 getter 函数(仅用于存取描述符) undefined
set function 属性的 setter 函数(仅用于存取描述符) undefined

2. 两种描述符类型

  1. 数据描述符(Data Descriptor)
    • 直接定义属性的值及特性:
const obj = {};
Object.defineProperty(obj, 'name', {
  value: 'Alice',      // 属性值
  writable: true,      // 可修改
  enumerable: true,    // 可枚举
  configurable: true   // 可配置
});

console.log(obj.name); // "Alice"
obj.name = 'Bob';      // 成功(writable: true)
  1. 存取描述符(Accessor Descriptor)
    • 通过 get/set 函数控制属性访问:
let _age = 18;
const obj = {};
Object.defineProperty(obj, 'age', {
  get() { return _age; },                    // 读取时返回 _age
  set(newVal) { if (newVal > 0) _age = newVal; }, // 设置时校验
  enumerable: true,
  configurable: true
});

console.log(obj.age); // 18
obj.age = -5;         // 设置失败(setter 校验)
console.log(obj.age); // 18

3. 关键特性详解

  1. writable
    • 控制属性值是否可修改:
Object.defineProperty(obj, 'id', {
  value: 1001,
  writable: false // 不可修改
});
obj.id = 2002;    // 静默失败(严格模式报错)
  1. enumerable
    • 控制属性是否可枚举:
Object.defineProperty(obj, 'secret', {
  value: 'hidden',
  enumerable: false // 不可枚举
});
console.log(Object.keys(obj)); // 不包含 'secret'
  1. configurable
    • 控制属性是否可删除或描述符是否可修改:
Object.defineProperty(obj, 'fixed', {
  value: 'constant',
  configurable: false // 不可配置
});
delete obj.fixed;     // 失败
// 尝试修改描述符会报错(如 writable: true)

4. 常用方法

方法 作用
Object.defineProperty(obj, prop, descriptor) 定义单个属性描述符
Object.defineProperties(obj, descriptors) 批量定义属性描述符
Object.getOwnPropertyDescriptor(obj, prop) 获取属性描述符
Object.getOwnPropertyDescriptors(obj) 获取对象所有属性的描述符

示例:

const car = {};
Object.defineProperties(car, {
  brand: {
    value: 'Tesla',
    enumerable: true
  },
  price: {
    value: 300000,
    writable: false
  }
});

const desc = Object.getOwnPropertyDescriptor(car, 'brand');
console.log(desc);
// { value: "Tesla", writable: false, enumerable: true, configurable: false }

5. 应用场景

  1. 封装私有属性
    • 通过闭包 + 存取描述符实现数据保护:
function createPerson(name) {
  let _name = name;
  const obj = {};
  Object.defineProperty(obj, 'name', {
    get() { return _name; },
    set(val) { _name = val.trim(); }
  });
  return obj;
}
  1. 禁止扩展/删除属性
    • 结合 configurable: false 冻结关键属性。
  2. 框架响应式原理
    • Vue 2 使用 Object.defineProperty 实现数据双向绑定(Vue 3 改用 Proxy)。

6. 注意事项

  1. 默认值差异
    • 直接赋值 vs defineProperty:
obj.a = 1; // 默认 writable/enumerable/configurable: true
Object.defineProperty(obj, 'b', { value: 2 }); // 默认全 false
  1. 严格模式
    • 违反 writable: false 或 configurable: false 时,严格模式会抛出错误。
  2. 原型链属性
    • Object.defineProperty 只能操作自身属性(非继承属性)。

总结
属性描述符是 JavaScript 对象系统的底层核心机制,通过精细控制属性的可写性、可枚举性、可配置性以及自定义存取逻辑,为开发者提供了强大的元编程能力。理解其工作原理有助于实现高级功能(如属性校验、响应式更新等),同时也是深入理解现代前端框架的基础。

你可能感兴趣的:(javascript,前端,开发语言,笔记)