Object.defineProperty()
Posted hj412
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Object.defineProperty()相关的知识,希望对你有一定的参考价值。
引言
今天就来了解一下
Object.defineProperty
方法,直到今天才发现原来有这么一个神奇的方法描述
该方法允许精确添加或修改对象的属性。通过赋值操作添加的普通属性是可枚举的,能够在属性枚举期间呈现出来(for...in 或 Object.keys 方法), 这些属性的值可以被改变,也可以被删除。这个方法允许修改默认的额外选项(或配置)。默认情况下,使用 Object.defineProperty() 添加的属性值是不可修改的。
参数 Object.defineProperty(obj, prop, descriptor)
- obj: 要在其上定义属性的对象。
- prop: 要定义或修改的属性的名称。
- descriptor: 将被定义或修改的属性描述符。
- 返回值: 被传递给函数的对象。
属性描述符
分为数据描述符和存储描述符
configurable、enumerable
数据、存储描述符共有,而value、writable
和get、set
只能拥有其中之一
说明
- configurable
- 当且仅当该属性的 configurable 为 true 时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除。
- enumerable
- 当且仅当该属性的enumerable为true时,该属性才能够出现在对象的枚举属性中(才能被例如for...in和Object.keys()遍历)。
- value
- 该属性对应的值。可以是任何有效的 javascript 值(数值,对象,函数等)。
- writable
- 当且仅当该属性的writable为true时,value才能被修改。
- get
- 一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。当访问该属性时,该方法会被执行,方法执行时没有参数传入,但是会传入this对象(由于继承关系,这里的this并不一定是定义该属性的对象)。
- set
- 一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。当属性值修改时,触发执行该方法。该方法将接受唯一参数,即该属性新的参数值。
configurable | enumerable | value | writable | get | set | |
---|---|---|---|---|---|---|
数据描述符 | Yes | Yes | Yes | Yes | No | No |
存取描述符 | Yes | Yes | No | No | Yes | Yes |
默认值 | false | false | undefined | false | undefined | undefined |
数据描述符示例
let data = {
name: '车神-黄杰',
age: 23
}
// 为data对象添加一个 gender属性 并把 writable设置为:true 该值可被修改
Object.defineProperty(data, 'gender', {
value : '男',
writable : true,
enumerable : true,
configurable : true
})
// 为data对象添加一个 like属性 并把 writable设置为:false 该值不可被修改,即使修改不会报错,但无效果
Object.defineProperty(data, 'like', {
value : '敲代码',
writable : false,
enumerable : true,
configurable : true
})
console.log('修改前')
console.log(data)
data.like = '还喜欢爬山'
data.gender = '女'
console.log('修改后')
console.log(data)
打印结果
- 可看到
like
属性无法修改,其他配置可自行测试
存取描述符示例
get
该方法在获取某对象的属性时调用,并且该属性值由该方法返回值决定,没有参数
set
该方法在设置某对象的属性值时调用,参数即为设置的属性值
let data = {}
let obj = {
name: '车神-黄杰',
age: 23
}
// name属性
Object.defineProperty(data, 'name', {
get(){
return obj.name
},
set(val){
obj.name = val
},
enumerable : true,
configurable : true
})
// age属性
Object.defineProperty(data, 'age', {
get(){
// 这里 不返回任何值 即默认返回 undefined
// return obj.age
},
set(val){
obj.age = val
},
enumerable : true,
configurable : true
})
data.name = '我爱前端'
data.age = 53
// 获取name数据
console.log('data.name: '+ data.name)
console.log('obj.name: '+ obj.name)
// 获取age数据
console.log('data.age: '+ data.age)
console.log('obj.age: '+ obj.age)
打印结果
修改了
data.name
属性,会调用set
方法,即会执行obj.name = val
,因此obj.name
设置为我爱前端,当获取data.name
属性值时,会调用get
方法,值即为该方法的返回值,即obj.name
,因此data.name
也为我爱前端同理
obj.age = 53
也无需在解释,但是为什么data.age
为undefined,我们可以看到已经把return obj.age
注释了,因此它的get
方法返回值为undefined
扩展
如果能明白
Object.defineProperty()
的基本用法,就不难明白Vue
组件data
为什么不是对象,而是一个函数了,官方文档说明Vue实例
其实是代理了对data
对象属性的访问,正如存取描述符示例的代码,data
其实也是代理了对obj
对象属性的访问,看下面的代码,
data1、data2
同时都代理了对obj
对象属性访问,当修改data2.name
值为che_hj,则data1.name
也设置为che_hj,这很明显就是不是我们想要的,修改data2.name
不应该影响data1.name
的值,因此obj
应该为一个函数,这样就行了吗?想多了,还需要再敲多两行代码才能实现我们想要的效果,不过这里就不再累赘了。
let obj = {
name: '车神-黄杰',
age: 23
}
let data1 = {}
let data2 = {}
// 对象data1
Object.defineProperty(data1, 'name', {
get(){
return obj.name
},
set(val){
obj.name = val
},
enumerable : true,
configurable : true
})
// 对象 data2
Object.defineProperty(data2, 'name', {
get(){
return obj.name
},
set(val){
obj.name = val
},
enumerable : true,
configurable : true
})
// 值修改为 che_hj
data2.name = 'che_hj'
console.log('obj.name: '+ obj.name)
console.log('data1.name: '+ data1.name)
console.log('data2.name: '+ data2.name)
打印结果
- 可以看到
data1.name
也设置为了che_hj
以上是关于Object.defineProperty()的主要内容,如果未能解决你的问题,请参考以下文章