vue中的defineProperty简介
在 Vue.js 中,Object.defineProperty
是一个非常重要的工具,特别是在 Vue 2.x 的响应式系统中。Vue 2.x 使用 Object.defineProperty
来劫持对象属性的 getter 和 setter,从而能够在数据变动时做出响应。
defineProperty的作用
静态方法Object.defineProperty() 直接在对象上定义新属性,或修改对象上现有的属性,并返回该对象。
语法:
Object.defineProperty(obj, prop, descriptor)
参数 :
默认值/子属性 | 默认值 | 含义 | ||
---|---|---|---|---|
obj | 要在其上定义属性的对象。 | Object | ||
prop | 要定义或修改的属性的名称或名称。 | sting | ||
descriptor | 正在定义或修改的属性的描述符。Object | configurable | false | 是否可以删除或编辑 |
enumerable | false | 能否枚举 | ||
value | undefined** | |||
writable | false | 能否修改 | ||
get | ||||
set |
创建一个对象obj,并定义一些值。再创建一个空对象target
var obj = {
count : 0,
list : [1,2,4]
}
var target = {
};
它主要有以下几个功能:
功能一:通过value设置属性值
由于Object.defineProperty可以给对象定义属性,我们通过value,可以动态地将obj对象的属性动态地添加给target中。
for (let key in obj){
Object.defineProperty(target,key,{
value: obj[key]
})
}
console.log(target);
输出结果:
成功获取到了obj中的属性值
功能二:通过writable设置是否可写/修改
1.当writable的值为false时
尝试将count的值从0改为10
for (let key in obj){
Object.defineProperty(target,key,{
value: obj[key],
writable: false
})
}
target.count = 10;//将count中的值0修改成10
console.log(target.count); //0 当writable为false时,无法改变count的值
当writable为false时,无法改变count的值
2.当writable的值为true时
尝试将count的值从0改为10
for (let key in obj){
Object.defineProperty(target,key,{
value: obj[key],
writable: true
})
}
target.count = 10;//将count中的值0修改成10
console.log(target.count); //10
功能三:通过enumerable设置属性值是否允许遍历
在上面的代码基础上,我们添加enumerable属性并尝试遍历target中的属性值
1.当enumerable的值为false时
for (let key in obj){
Object.defineProperty(target,key,{
value: obj[key],
writable:true,
enumerable: false
})
}
for (key in target){
console.log(key);//遍历target中的属性值并打印,此时结果为空
}
2.当enumerable的值为true时
for (let key in obj){
Object.defineProperty(target,key,{
value: obj[key],
writable:true,
enumerable: ture
})
}
for (key in target){
console.log(key);//遍历target中的属性值并打印,此时结果为空
}
输出结果:
成功遍历对象并打印出结果
功能四:通过configurable设置属性是否可删
在上面的代码基础上,我们添加configurable属性并尝试用delete方法删除target中的属性
1.当configurable的值为false时
for (let key in obj){
Object.defineProperty(target,key,{
value: obj[key],
writable:true,
enumerable: false,
configurable: false
})
}
delete target.count;//删除count属性
console.log(target);
输出结果:
由于此方法为fasle时,属性值无法删除,target中仍有count属性
2.当configurable的值为true时
for (let key in obj){
Object.defineProperty(target,key,{
value: obj[key],
writable:true,
enumerable: false,
configurable: true
})
}
delete target.count;//删除count属性
功能五:通过get方法获取属性的值
【注意!】当设置get方法时,不能有value和writable方法,否则会报错
get方法的值是一个函数,此函数不需要参数
for (let key in obj){
Object.defineProperty(target,key,{
//value: obj[key],
//writable:true,
enumerable: false,
configurable: true,
get: function(){
return obj[key]
}
})
}
console.log(target.count);
输出结果:
成功获取到了指定属性(count)的值
功能六:通过set方法设置属性的值
set方法的值也是一个函数,定义时会自动注入一个参数,此参数会设置属性的值
for (let key in obj){
Object.defineProperty(target,key,{
//value: obj[key],
//writable:true,
enumerable: false,
configurable: true,
get: function(){
return obj[key]
},
set: function(val){
console.log(val);//打印设置好的值
}
})
}
target.count = 10;//修改count属性的值为10
输出结果:
成功修改了指定属性(count)的值
【注意】set方法只有在设置/修改指定属性值的时候,才会触发,即调用set下的匿名函数
vue2为什么使用Object.defineProperty
通过上述Object.defineProperty的使用介绍,我们可以知道,Vue 2.x 的响应式系统选择使用 Object.defineProperty
,主要是基于以下原因:
- 兼容性:
Object.defineProperty
是 ECMAScript 5.1 标准的一部分,因此在 Vue 2.x 发布时,它具有很好的浏览器兼容性。这使得 Vue 能够在多种浏览器环境中运行,而无需使用额外的转换工具或库。 - 实现简单:使用
Object.defineProperty
可以直接在一个对象上定义新属性,或者修改一个对象的现有属性,并为其添加 getter 和 setter。这使得 Vue 可以轻松地拦截属性的访问和修改,从而实现数据的响应式更新。 - 性能考虑:虽然
Object.defineProperty
在某些情况下可能不是最优的选择(例如,当需要频繁添加或删除属性时),但在 Vue 的应用场景中,它通常能够提供足够的性能。Vue 主要用于构建用户界面,而不是进行大量的数据操作,因此Object.defineProperty
的性能限制在 Vue 的上下文中通常是可以接受的。 - 与 Vue 的设计目标相契合:Vue 的设计目标之一是使开发者能够轻松地构建用户界面,而无需深入了解底层技术细节。使用
Object.defineProperty
可以帮助 Vue 隐藏这些底层细节,使开发者能够更专注于构建用户界面。
为什么Vue3废弃了Object.defineProperty
Vue3废弃Object.defineProperty
,一部分原因就是因为其有其局限性。
例如,它不能检测对象属性的添加或删除,也不能很好地处理数组索引和长度的变化。
为了解决这些问题,Vue 提供了一些额外的工具和方法(如
Vue.set
、Vue.delete
和一些特殊的数组方法),但这些方法需要开发者显式地调用。
因此,在 Vue3.x 中,响应式系统得到了改进,使用了 Proxy 而不是 Object.defineProperty
。
Proxy 可以提供更全面和灵活的数据劫持能力,能够检测更多的数据变动情况,包括对象属性的添加和删除以及数组索引和长度的变化。这使得 Vue 3.x 的响应式系统更加强大和易用。