十分钟带你一次弄懂Object.defineProperty

使用场景

我们对于对象的使用,有以下操作:

创建对象: let obj = {}

给obj对象的name属性赋值: obj.name = 'sanmu'

将obj的name属性赋值给变量name: const name = obj.name

调用obj的某个方法: obj.func()

除了上面的一些操作,我们还可以通过 Object.defineProperty 来定义新的属性或修改原有的属性,并返回此对象。

简单的认为,Object.defineProperty 可以使定义的属性操作更加多样化,而不是仅仅就是获取或者赋予值。

定义

Object.defineProperty(obj, prop, descriptor)

参数

obj: 要定义属性的对象。

prop: 要定义或修改的属性的名称。

descriptor: 要定义或修改的属性描述符。

返回值

被传递给函数的对象。

对于我们上面定义的 obj.name 中,obj 对应的参数 obj,name 对应参数 prop。

至于 descriptor 稍微复杂一些,它有两种形式:数据描述符存储描述符

数据描述符: 一个具有值的属性,该值可写可不写

存储描述符: 由 getter 函数和 setter 函数所描述的属性。

descriptor要不是数据描述符,要不就是存储描述符,不能同时是两者。

数据描述符存储描述符都是对象。

它们都有以下属性:

configurable: 值为boolean。当值为 true 时,obj 的的属性能够被改变,也能够被删除。默认为 false

enumerable: 值为boolean。当值为 true 时,obj 的属性才会出现在对象的枚举属性中(可以被for...in 或者 Object.keys直接获取到的属性)。默认为 false

const obj = {name: 'sanmu', age: 18}
Object.keys(obj) 
// 输出name, age,这里的name和age都是可枚举属性。若给age增加 enumerable=false,
// 则age变无法被获取到

数据描述符独有的属性:

value: obj 的属性对应的值。默认 undefined。

writeable: 值为boolean。当值为 true 时,obj 的属性的值就是上面的value。默认为 false

存储描述符独有的属性:

get: 属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。 默认为 undefined

set: 属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。 默认为 undefined

configurableenumerablevaluewritablegetset
数据描述符可以可以可以可以不可以不可以
存取描述符可以可以不可以不可以可以可以

所以,我们描述一个对象的属性可以是如下方式

const obj = {name: 'sanmu'}
Object.defineProperty(obj, 'name', {
  configurable: true | false,
  enumerable: true | false,
  value: '任意类型的值',
  writable: true | false
})

举例

首先,先创建一个对象

const obj = {}

给 obj 对象增加一个 name 属性,并且给它的 value 赋予 sanmu

const obj1 = {}
Object.defineProperty(obj1, 'name', {
    value: 'sanmu'
})
console.log(obj1.name) // 输出sanmu

writable

接着,我们给 writable ,它可以控制属性值是可以被重写。

// writable: false
const obj2 = {}
Object.defineProperty(obj2, 'name', {
    value: 'sanmu',
    writable: false
})
obj2.name = 'new sanmu' // 将name的属性赋予新value new sanmu
console.log(obj2.name) // 输出还是 sanmu

可以看到,当 writable = false的时候,虽然我们给name=‘new sanmu’,但是实际上并没有被修改。


// writable: true
const obj3 = {}
Object.defineProperty(obj3, 'name', {
    value: 'sanmu',
    writable: true
})
obj3.name = 'new sanmu' // 将name的属性赋予新value new sanmu
console.log(obj3.name) // 输出 new sanmu

当 writable = true,name被改成了new samu

enumerable

可以控制对象的属性是否能够被枚举。

首先,给 name 属性增加 enumerable = false,我们输出 Object.keys(obj)

const obj4 = {}
Object.defineProperty(obj4,'name', {
    enumerable: false
})
console.log(Object.keys(obj4)) // 输出 []

可以看到虽然 name 是 obj 的属性,但是并没有被输出。

const obj5 = {}
Object.defineProperty(obj5,'name', {
    enumerable: true
})
console.log(Object.keys(obj5)) // 输出 ['name']

enumerable = true,name 属性就可以被正常输出了

cofigurable

用于控制对象的属性是否可以被删除。若configurable = true,可以被删除;否则不可以。

我们先给 configurable = true,

const obj6 = {}
Object.defineProperty(obj6, 'name', {
  configurable: true,
  value: 'sanmu' 
})

console.log(obj6.name) // 输出 sanmu
delete obj6.name
console.log(obj6.name) // 输出 undefined

再给 configurable = false

const obj7 = {}
Object.defineProperty(obj7, 'name', {
  configurable: false,
  value: 'sanmu' 
})
consolle.log(obj7.name) // 输出 sanmu
delete obj7.name
console.log(obj7.name) // 输出 sanmu

get/set

getter和setter方法用于给对象的属性设置或者获取。

比如我们使用 obj.name = 'sanmu',给name属性赋予值是sanmu,就是触发了set方法。

const name = obj.name就是触发了get方法 

const obj8 = {name: 'sanmu'}
let value
Object.defineProperty(obj8,'name',{
    get: function() {
       return 1
    },
    set: function(val) {
       value = val 
    }
})


obj8.name = 'new sanmu'
onsole.log(obj8.name) // 输出1
console.log(value) // 'new sanmu'

可以看到当我给 obj8.name = 'new sanmu' 时,触发了 set 方法,给value 赋予 'new sanmu'。

输出 obj8.name 的时候,触发 get 方法,这里return 1,从而我们获取name属性真实的值,被拦截了。

引用:

深入理解 Object.defineProperty 及实现数据双向绑定 - 龙恩0707 - 博客园

Object.defineProperty() - JavaScript | MDN

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值