理解Object.defineProperty的作用

本文详细解析了Object.defineProperty方法,包括其参数与属性描述符的作用,如value、writable、enumerable和configurable等。并通过实例展示了如何利用此方法实现数据劫持,如Vue中的数据双向绑定原理,并提供了一个使用defineProperty解决异步状态判断问题的实际案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

defineProperty的属性

Object.defineProperty定义新属性或修改原有的属性 

Object.defineProperty(obj, prop, descriptor)

参数说明:

obj:必需。目标对象 
prop:必需。需定义或修改的属性的名字
descriptor:必需。目标属性所拥有的特性

descriptor里面的属性都是可选的,每一个属性的作用如下,具体的使用方法详见官方文档,这里只是大致罗列出来个属性

  1. value 该属性对应的值,可以是任意类型的值,默认为undefined
  2. writeable 该属性的值是否可以被重写 默认是false不能被重写
  3. enumberable 该属性是否可以被枚举(使用for...in 或者Object.keys()能遍历出来)默认是false 不可被枚举
  4. configurable 是否可以删除目标属性或是否可以再次修改属性的特性(writable, configurable, enumerable)。设置为true可以被删除或可以重新设置特性;设置为false,不能被可以被删除或不可以重新设置特性。默认为false。

    这个属性起到两个作用:目标属性是否可以使用delete删除 目标属性是否可以再次设置特性

第5个属性就是存取器(注意:当使用了getter或setter方法,不允许使用writable和value这两个属性)

 相信用过vue的同学,对vue的数据双向绑定的原理有一定的了解,那就是数据劫持,就是用的Object.defineProperty这个方法,里面定义了setter和getter方法,通过观察者模式(发布订阅模式)来监听数据的变化,从而做相应的逻辑处理。

  let obj = {}
  let initVal = 123
  Object.defineProperty(obj, 'age', {
    set: function(val) {
      console.log("改变")
      initVal = val
    },
    get: function() {
      return initVal
    }
  })
  console.log(obj.age) // 执行get 方法 输出123
  obj.age = 456 // 执行set 方法 输出改变 这时的initVal 赋值为456
  console.log(obj.age) // 输出456

这里就具体讲解vue数据双向绑定的原理了,这里分享一个通过defineProperty解决异步状态判断的问题。在实际项目中H5与原生APP的交互还是很多,这里我们定下的协议就是 调用原生的方法的时候,必须先调用ready初始化方法,只有调用ready成功后,才能调用后续的方法,后续的方法这里用getUserInfo方法作为例子

// 正常采用promise的处理
  
  function Ready(){
    retrun new Promise((resolve,reject)=>{
        // 原生的ready 方法
        function ready(){
            resolve()
        }
        ready()
    })
  }
  Ready().then(()=>{
    getUserInfo()
  })

但是实际情况的话,加上jsBridge,会显得很复杂,实现起来也不是很简单 考虑的就是定义一个全局变量stats 设置为false,在ready放法中改变state的值,触发set 方法 通过判断来执行 resolve,

  let _resolve = null; // 用来将promise的resovle 保存 延迟将Promise对象的状态从“未完成”变为“成功”
  let promise = new Promise(resolve => {_resolve=resolve})
  let obj = {}
  let _state = false
  Object.defineProperty(obj, 'state', {
    set: function(val) {
      !state && val && _resolve ()
      _state = val
    },
    get: function() {
      return _state 
    }
  })
  // 这里的then方法不会立马被调用 因为没有执行resovle 
  promise.then(()=>{
    getUserInfo()
  })
  // 模拟异步调用 原生的方法
  setTimeOut(()=>{
      obj.state = true 
  },1000)

这只是一个简答的例子,实际运用的时候会有点出入,掌握这个思想最为重要,其次对promise的理解要深刻。

### JavaScript 中 `Object.defineProperty` 的用法与参数详解 #### 方法概述 `Object.defineProperty` 是 JavaScript 提供的一个静态方法,用于直接在一个对象上定义一个新的属性或修改现有的属性,并返回该对象。这种方法可以精确地控制属性的行为,包括其可写性、可枚举性和可配置性等特性。 #### 方法签名 以下是 `Object.defineProperty` 的基本语法结构: ```javascript Object.defineProperty(obj, prop, descriptor); ``` - **obj**: 被操作的目标对象。 - **prop**: 需要被定义或修改的属性名称(字符串形式)。 - **descriptor**: 属性描述符,指定属性的具体行为和特征。 --- #### 描述符类型 `Object.defineProperty` 支持两种类型的描述符:**数据描述符** 和 **存取器描述符**。这两种描述符不能同时存在于同一个属性中[^1]。 ##### 数据描述符 数据描述符表示的是那些具有值的属性。它们可以通过以下键来设置: - **value**: 属性的默认值,默认为 `undefined`[^2]。 - **writable**: 表明属性是否可以更改,默认为 `false`[^3]。 - **enumerable**: 表明属性是否可以在枚举过程中被发现,默认为 `false`。 - **configurable**: 表明属性是否可以重新定义或删除,默认为 `false`。 示例代码如下: ```javascript const obj = {}; Object.defineProperty(obj, 'name', { value: 'John', writable: false, enumerable: true, configurable: false }); console.log(obj.name); // 输出 John obj.name = 'Doe'; // 不起作用,因为 writable 设置为 false delete obj.name; // 删除失败,因为 configurable 设置为 false for (let key in obj) { console.log(key); } // 枚举到 name,因为 enumerable 为 true ``` ##### 存取器描述符 存取器描述符不包含 `value` 或 `writable` 键,而是提供了一种机制来拦截对该属性的访问和赋值操作。它支持以下两个函数作为键: - **get**: 获取属性时调用的函数,默认为 `undefined`。 - **set**: 设置属性时调用的函数,默认为 `undefined`。 需要注意的是,如果提供了 `get` 或 `set` 函数,则不允许再使用 `value` 或 `writable` 这些关键字。 示例代码如下: ```javascript const person = {}; Object.defineProperty(person, 'age', { get() { return this._age; }, set(value) { if (typeof value !== 'number' || value < 0) { throw new Error('年龄必须是非负数'); } this._age = value; }, enumerable: true, configurable: true }); person.age = 25; // 正常工作 console.log(person.age); // 输出 25 try { person.age = -5; // 抛出错误 } catch(e) { console.error(e.message); } ``` --- #### 使用场景 `Object.defineProperty` 常见的应用场景包括但不限于以下几个方面: 1. 定义只读属性,防止意外修改。 2. 创建不可枚举的私有属性。 3. 实现自定义 gettersetter 来增强属性的功能。 4. 控制对象的状态变化,比如实现响应式编程的基础逻辑。 --- #### 注意事项 尽管 `Object.defineProperty` 功能强大,但在实际开发中有几点需要注意: - 如果目标对象是冻结的对象(frozen object),则无法成功定义新的属性或修改已有属性。 - 对于数组长度的操作可能会影响性能,因此应谨慎处理涉及数组的情况。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值