Object.defineProperty 的用法

32 篇文章 0 订阅

简介

Object.definePropety() 方法可以直接在一个对象上定义一个新属性,或者修改一个已经存在的属性,并返回此对象。

描述

Object.defintPropety(data, key, descriptor)
该方法允许精确地添加或修改对象的属性。通过赋值操作添加的普通属性是可枚举的,在枚举对象属性时会被枚举到(for…in 或 Object.keys 方法),可以改变这些属性的值,也可以删除这些属性。这个方法允许修改默认的额外选项(或配置)。默认情况下,使用 Object.defineProperty() 添加的属性值是不可修改(immutable)的。

参数

  1. data 须要定义属性的对象
  2. key 需被定义或修改的属性名
  3. descriptor 要定义或修改的属性的描述符

descriptor 详细参数

configurable 该属性的 configurable 为 true 时,该属性才可以被修改或能够经过 delete操作符删除该属性,默认为 false (将属性设置为只读,不可修改也不可删除)
enumerable 该属性的 enumerable 为 true 时,该属性才可以出如今对象的枚举属性中,默认false
value 该属性对应的属性值,可以为任何有效的 JS 值,默认为 undefined
writable 当该属性的 writable 为true时,该属性才能被赋值运算改变,默认为false(将属性设置为不可枚举)
get 属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。 (简单的说就是,当没有设置get 属性的时候,访问属性会默认返回属性值,配置这个函数的时候可以监听到访问的属性以及属性值,可以支持处理不同的操作,比如说给书籍增加《》。)
set 属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值)。 (配置这个函数的时候,可以监听到属性的修改,以及修改的新值)

使用示例

若是当前对象不存在要设置的属性,Object.defineProperty() 会根据方法设置为对象创建一个新的属性

let data = {} // 创建一个空对象
let age = 18
Object.defineProperty(data, 'age', {
  // value: age,
  // configurable: false, // --> 是否可以通过 delete 操作符删除该属性
  // enumerable: false, // --> 循环的时候, 是否可以被枚举出来
  // writable: false, // --> 是否可以使用 ++, -- 等操作符
  get() { // -->  当属性被访问的时候触发, 这个方法里需要返回一个值, 否则访问的时候会报错
    console.log(`访问了age`);
    return age  // 返回一个值
  },
  set(newValue) { // -->  当属性被修改的时候出发, 需要给原来的属性赋值为新值, 否则对象中保存的值还是旧的值
    console.log(`触发了修改age, 新值为${newValue}`);
    age = newValue // 修改
  }
})

setTimeout(() => {
  console.log(data); // 访问对象
  console.log('添加绑定后的值为', data.age); // 查看属性绑定是否会触发 getters 的监听
  data.age = 30 // 修改值后查看, 属性是否触发 Setters 的监听
  console.log('修改后的值为', data.age); // 查看修改后的值
}, 200)

代码输出结果

在这里插入图片描述
这里我们可以看到添加的双向绑定已经生效了, 当我们访问,修改 age 属性的时候,都会触发get,set 监听,我们可以在这些监听里面做相应的操作。

封装 Object.defineProperty

因为原生的 Object.defineProperty 并不是很好用,所以我们在使用到它的地方,进行二次封装让它更好用一些。

function definedReactive(data, key, value){
	if (!value) {
		value = data[key]
	}
	Object.defineProperty(data, key, {
		// ... 这里写个性化配置
	})
}

这样的话,调用的时候就只需要调用 definedReactive 方法传入对应的值就可以让对象变成相应式的数据了。

拓展

这个 JS 的原生属性对数组的支持并不是很友好,监听不到数组下标变化、数组的 push pop shift slice splice 等方法对原数组的修改,及对象新增属性,因为监听的不是对象本身,而是对象属性。
同时性能和可扩展性上面也不如 ES6(ESMAScript2015)中提出的 proxy 支持度更好一些。

在 Vue3 中使用 Proxy 代替 Object.defineProperty 重构了响应式系统,可以监听到数组下标变化,及对象新增属性,因为监听的不是对象属性,而是对象本身,还可拦截 apply、has 等 13 种方法

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值