Skip to content
On this page

Object.defineProperty 详解

基本概念

Object.defineProperty() 是 JavaScript 中一个强大的方法,它允许我们精确地添加或修改对象的属性。通过这个方法,我们可以定义属性的各种特性,如属性是否可写、可枚举、可配置等。

javascript
Object.defineProperty(obj, prop, descriptor)

参数说明:

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

属性描述符

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

数据描述符

数据描述符包含以下可选键值:

  • value:属性的值,默认为 undefined
  • writable:属性值是否可以被修改,默认为 false
  • enumerable:属性是否可以被枚举(如在 for...in 循环中),默认为 false
  • configurable:属性是否可以被删除或修改特性,默认为 false

访问器描述符

访问器描述符包含以下可选键值:

  • get:获取属性值的函数,默认为 undefined
  • set:设置属性值的函数,默认为 undefined
  • enumerable:同数据描述符
  • configurable:同数据描述符

为对象添加不可修改、不可删除的方法

在实际开发中,我们经常需要为对象添加一些核心方法,并确保这些方法不会被意外修改或删除。这时,Object.defineProperty 就派上用场了。

示例代码

javascript
Object.defineProperty(uni.$componentsRows, 'get', {
  value: function (name) {
    let item = this.find((item) => item.name === name)
    if (!item) return {}
    return cloneDeep(item)
  },
  writable: false, // 不允许修改
  configurable: false, // 不允许删除
})

在这个示例中:

  1. 我们为 uni.$componentsRows 对象添加了一个名为 get 的方法
  2. 该方法接收一个 name 参数,查找并返回匹配的项目的深拷贝
  3. writable: false 确保该方法不能被重新赋值
  4. configurable: false 确保该方法不能被删除,也不能修改其描述符

属性特性的作用

writable: false

writable 设置为 false 时,尝试修改属性值会失败(在严格模式下会抛出错误):

javascript
uni.$componentsRows.get = function () {
  return 'hacked'
} // 无效操作
console.log(uni.$componentsRows.get('test')) // 仍然执行原来的函数

configurable: false

configurable 设置为 false 时:

  1. 不能删除该属性
  2. 不能修改该属性的描述符(除了 writable 可以从 true 改为 false)
javascript
delete uni.$componentsRows.get // 无效操作
Object.defineProperty(uni.$componentsRows, 'get', { enumerable: true }) // 抛出错误

实际应用场景

1. 创建常量属性

javascript
const config = {}
Object.defineProperty(config, 'API_URL', {
  value: 'https://api.example.com',
  writable: false,
  configurable: false,
})

2. 保护核心方法

javascript
const api = {
  data: [],
}

Object.defineProperty(api, 'fetch', {
  value: async function () {
    // 实现获取数据的逻辑
    this.data = await fetchData()
    return this.data
  },
  writable: false,
  configurable: false,
})

3. 实现私有属性

javascript
function createUser(name) {
  const user = {}

  Object.defineProperty(user, '_password', {
    value: '',
    writable: true,
    enumerable: false, // 不可枚举,在遍历对象时不会出现
  })

  Object.defineProperty(user, 'name', {
    value: name,
    writable: false,
  })

  Object.defineProperty(user, 'setPassword', {
    value: function (pwd) {
      this._password = pwd
    },
    writable: false,
    configurable: false,
  })

  return user
}

注意事项

  1. 默认值:如果不指定 writableenumerableconfigurable,它们的默认值都是 false
  2. 不可逆性:一旦属性被设置为不可配置(configurable: false),就无法再将其改回可配置
  3. 严格模式:在严格模式下,尝试违反这些限制会抛出错误;非严格模式下只会静默失败
  4. 性能考虑:大量使用 Object.defineProperty 可能会影响性能,特别是在频繁创建对象的场景

总结

Object.defineProperty 是 JavaScript 中一个强大的工具,它允许我们精确控制对象属性的行为。通过设置 writable: falseconfigurable: false,我们可以创建不可修改、不可删除的方法或属性,从而提高代码的健壮性和安全性。

在实际开发中,合理使用这一特性可以帮助我们创建更可靠的 API,防止关键方法被意外覆盖或删除,同时也能更好地实现封装和信息隐藏的设计原则。

要保持清醒 永远不抱有意外的幻想 凭空的期待最要命