如何在对象上添加一个属性?
-
首先我们能很简单的想到
const obj = {} obj.a = 1 //在obj对象上添加了一个属性名为a,值为1的属性 console.log(obj.a) // 1 obj.hasOwnProperty('a') // true obj['b'] = 2 //以[]的方式添加属性 console.log(obj['b']) // 2我们可以对该属性进行正常的读取与修改
-
还有一种比较高级的添加属性方式就是Object.defineProperty()
例如我们可以通过以下方式给对象添加一个属性:
const obj = {a:1} Object.defineProperty(obj,'b',{ value:2 }) console.log(obj) // {a: 1, b: 2}我们发现已经成功的向obj这个对象上添加了一个属性名为b,值为2的属性,
但在我们使用这个对象时我们会发现以下情况:
obj.b = 3 // 当我们尝试将b的值修改为3时 console.log(obj) // {a: 1, b: 2} 输出可以看到b的值便没有改变 // 以及 Object.keys(obj) // 当我们尝试读取obj的所有key时,输出为['a'] for(let item in obj){ console.log(item) } // 被输出的同样只有a一个属性可以发现的是,由
Object.defineProperty()定义的属性b变得不可被修改及不可被遍历了,这是为什么呢?接下来我们从javascript的对象属性修饰符开始解答。
属性修饰符
- 什么是属性修饰符?JavaScript中,属性修饰符是用来控制对象属性行为的标志,这些修饰符定义了该属性如何响应各种操作。其中主要包括了数据描述符与访问器描述符。
数据描述符
数据描述符直接是关联到的是属性的值,主要有以下特性:
value:属性的值,可以是javascript中的任意有效值(各字面量、变量等)writable:值应为一个布尔值,表示属性的值是否可被修改。默认为false,此时任何试图修改该属性的操作都会被忽略。enumerable:值应为一个布尔值,表示属性是否可以在for...in循环、Object.keys()、Object.getOwnPropertyNames()等操作中被枚举出来。默认为false,此时该属性在迭代对象属性时会被隐藏。configurable:值应为一个布尔值,表示属性描述符是否可被修改,以及该属性能否可以从对象中被删除。默认为false,此时writable、enumerable、configurable本身以及value都不能被修改,并且该属性不能被删除。
const obj = {}
Object.defineProperty(obj,'a',{
value:1
})
// 此时我们定义了一个名为a值为1的属性,它不能被修改、遍历
Object.defineProperty(obj,'a',{
value:1,
writable:true
})
// 此时属性a可以被修改
Object.defineProperty(obj,'a',{
value:1,
writable:true,
enumerable:true
})
// 此时属性a可以被遍历
Object.defineProperty(obj,'a',{
value:1,
writable:true,
enumerable:true,
configurable:false
})
delete obj.a // false
// 此时属性a的修饰符无法更改且属性无法被删除
访问器描述符
访问器描述符使用get和set函数来定义属性的读取和写入行为,而不是直接关联一个值,主要具有以下特性:
get:为一个函数,无参数,当属性被访问时调用。返回值即为属性值。set:为一个函数,接受一个参数为新的属性值,当属性被修改时调用,没有返回值
const obj = {}
let n = 4
obj.a = n // 当我们想要把一个属性的值关联为一个变量的值时
console.log(obj.a) // 输出为4
n = 5
console.log(obj.a) //输出仍为4,我们发现a并没有随n的改变而改变
// 但如果我们使用get与set
Object.defineProperty(obj,'a',{
get(){
return n
},
set(value){
n = value
}
})
console.log(obj.a) // 输出5,
n = 6 // 当我们再去改变n时
console.log(obj.b) // 输出6,我们可以发现我们以及将n与obj的属性a关联了起来
为什么要Object.defineProperty()?
- 从上述内容我们其实已经可以看出
Object.defineProperty()使我们精确地添加或修改对象上的属性,其实Object.defineProperty()就是允许我们自定义对象属性的属性描述符。
用法
Object.defineProperty(obj,prop,descriptor)该方法有三个参数,分别是:
obj:要定义属性的对象。prop:字符串,指定要定义或修改的属性键。descriptor:要定义或修改的属性描述符。
作用
- 首先我们知道可以通过该方法来设计和控制对象的行为,精确控制属性的特性。
- 我们可以通过该方法创建不可更改(只读)或不可删除的属性,有助于增强代码的安全性和减少意外修改的风险。
- 可以定义getter和setter方法,允许你在读取或设置属性值时执行额外的逻辑,这对于数据验证、计算属性或触发副作用(如事件通知)特别有用。
vue2中的Object.defineProperty()
-
在vue2中,
Object.defineProperty()是实现数据绑定和响应式系统的核心技术之一。vue通过遍历数据对象的所有属性,并使用Object.defineProperty()为每个属性添加getter和setter,从而实现数据变化的追踪和视图自动更新。主要过程大致如下:
- 数据劫持:Vue在初始化时会遍历用户定义的数据对象,对每个属性执行
Object.defineProperty()。这个过程被称为“数据劫持”,因为它改变了属性的默认行为。 - Getter:vue会为每一个属性定义一个getter,当访问这个属性使会被自动调用,同时其还负责记录依赖。当一个属性被读取时,vue会知道哪些计算属性或视图正在依赖于这个值,从而构建一个依赖关系图。
- Setter:vue会为每一个属性定义一个setter,并在其中加入更新机制。当属性值发生变化时,setter会通知vue,vue随后会检查依赖于这个值的所有部分,并执行必要的DOM更新。
- 数据更新:应为在vue实例上的数据都由
Object.defineProperty()进行了代理,所以当我们读取或修改属性时都会被vue捕获从而实现数据与视图的同步更新。
这并是
Object.defineProperty()在完成vue2响应式中实现的强大功能。 - 数据劫持:Vue在初始化时会遍历用户定义的数据对象,对每个属性执行
最后谢谢你的阅读,如果觉得写的好的话就给我点个赞吧🥰🥰🥰,哪里写的有问题的地方还望指正。