object.defineProperty()随笔

博客介绍了通过Object.defineProperty定义属性的相关知识,包括三个参数及属性描述符的各参数值。还指出Vue.js采用数据劫持结合发布 - 订阅者模式,利用Object.defineProperty劫持属性的setter、getter,数据变动时触发监听回调实现数据双向绑定。

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

通过Object.defineProperty 定义一个属性

Object.defineProperty(object, propertyname, descriptor);
一共有三个参数。
object:必须,要在其上添加或修改属性的对象。
propertyname:必需。 一个包含属性名称的字符串。
descriptor: 属性描述符。 它可以针对数据属性或访问器属性

descriptor:有以下参数值
value:  属性的值,默认为 undefined。
writable:  该属性是否可写,如果设置成 false,则任何对该属性改写的操作都无效(但不会报错,但是在严格模式下会报错。),对于像前面例子中直接在对象上定义的属性,这个属性该特性默认值为为 true。
configurable:总开关,一旦为false,就不能再设置他的(value,writable,configurable)

enumerable:定义了对象的属性是否可以在 for...in 循环和 Object.keys() 中被枚举。

get: 对定义的属性取值的时候会触发get 对应的函数,并且返回结果,默认返回undefined。

set: 对定义的属性赋值的时候会触发set 对应的函数

 

vue.js采用的是数据劫持结合发布和-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调

### Object.defineProperty的缺点 #### 1. 无法监听新增属性 `Object.defineProperty`只能劫持对象已存在的属性,当新增属性时,它无法检测到变化。例如: ```javascript const obj = {}; Object.defineProperty(obj, 'name', { get() { console.log('读取name'); }, set() { console.log('修改name'); } }); obj.name = '张三'; // 能触发setter obj.age = 18; // 无法触发任何反应!新增属性时Object.defineProperty根本不知道 ``` 这意味着如果对象需要动态添加属性并希望这些属性也具有响应性,必须手动重新定义这些属性的描述符。 #### 2. 无法监听删除属性 同样,当从对象中删除属性时,`Object.defineProperty`也无法检测到这一变化: ```javascript delete obj.name; // 同样无法触发反应! ``` 这导致了在处理对象属性的增删时,开发者需要额外的工作来确保状态的一致性和响应性。 #### 3. 对数组的支持有限 `Object.defineProperty`对数组的支持有限,特别是对于数组的方法调用(如`push`, `pop`, `shift`, `unshift`, `splice`, `sort`, `reverse`)不会触发属性的`set`方法。为了克服这个问题,Vue 2.x通过重写数组的方法来实现对数组变化的监听。 #### 4. 需要递归遍历对象 为了使对象的所有嵌套属性都具有响应性,需要递归地对每个属性应用`Object.defineProperty`。这不仅增加了代码的复杂度,而且对于大型对象来说,这可能会导致性能问题。 ```javascript function Observer(obj) { let keys = Object.keys(obj); for (let i of keys) { if (typeof obj[i] == 'object' && obj[i] !== null) { Observer(obj[i]); } Object.defineProperty(obj, i, { get() { console.log(`数据被获取了${obj[i]}...`); return obj[i]; }, set(newValue) { console.log(`数据变化了,obj.${i}:${newValue}...`); obj[i] = newValue; }, enumerable: true, configurable: true }); } } ``` #### 5. 不支持对整个对象的操作 `Object.defineProperty`只能拦截对象的属性访问,对于对象的整体操作(如对整个对象的赋值或属性遍历)并不会被拦截。这限制了其在某些场景下的灵活性和实用性。 ### 相关问题 1. 如何在JavaScript中使用Proxy来解决Object.defineProperty的局限性? 2. Vue 3.0中使用Proxy替代Object.defineProperty的具体实现方式是什么? 3. 在JavaScript中,如何通过自定义方法来实现对数组变化的监听? 4. 什么是Vue.set和Vue.delete,它们是如何帮助解决Object.defineProperty的局限性的? 5. 如何评估Object.defineProperty和Proxy在JavaScript中的性能差异?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值