Object.defineProperty() 详解

一、对象的定义与赋值

我们经常使用的定义与赋值方法 obj.xxx = value 或 obj['xxx'] = value,并且可以定义任意类型的值,如下所示:

let obj = {};
obj.name = 'bjl';
obj['age'] = 18;
obj.sayHi = function() {console.log('Hi')};
console.log(obj)  // {name: 'bjl', age: 18, sayHi: fn}

二、Object.defineProperty() 语法

Object.defineProperty() 的作用就是直接在一个对象上定义新属性,或者修改一个已经存在的属性。语法格式为:

Object.defineProperty(object, propName, descriptor);
  1. object:需要定义属性的当前对象
  2. propName:当前需要定义的属性名
  3. descriptor:属性描述符

三、属性描述符

都有哪些属性描述符呢?如下:

  • value:设置属性的值
  • writable:值是否可以重写
  • set:目标属性设置值的方法
  • get:目标属性获取值的方法
  • enumerable:目标属性是否可以被枚举(是否可以遍历)
  • configurable:目标属性是否可以被删除或是否可以再次修改特性

通过 Object.defineProperty() 为对象定义属性有两种形式,但不能混合使用,分别是数据描述符、存取描述符。

1. 数据描述符(value、writable)

当使用了 value 和 writable 属性,不允许使用 getter 或 setter 这两个方法。

  • value:设置属性值
let obj = {};
Object.defineProperty(obj, 'name', {
    value: 'bjl'
})
console.log(obj.name)  // bjl
  • writable:描述对象是否可写,默认值为false,表示只读属性
let obj = {};
Object.defineProperty(obj, 'name', {
    value: 'bjl'
})
obj.name = 'bao';
console.log(obj.name)  // bjl
let obj = {};
Object.defineProperty(obj, 'name', {
    value: 'bjl',
    writable: true // 表示可以进行修改
})
obj.name = 'bao';
console.log(obj.name)  // bao
let obj = {
    name: 'bjl'
};
Object.defineProperty(obj, 'name', {
    writable: false  //手动设置name属性不可被修改
})
obj.name = 'bao';
console.log(obj.name)  // bjl

当声明一个对象时,它里面的属性的内部属性的默认值都为 true,也就是说 writable 这时的默认值为 true,这就是为什么上面的 name 如果不想被修改就需要手动去设置 writable 属性的原因。我们可以使用 Object.getOwnPropertyDescriptors() 去检测属性的内部属性的具体描述,如下:

let obj = {
    name: 'bjl'
}    
console.log(Object.getOwnPropertyDescriptors(obj))

Object.defineProperty(obj, 'age', {
    value: 18
})
console.log(Object.getOwnPropertyDescriptors(obj))

打印如下:

 2. 存储描述符(get、set)

当使用 get 或 set 方法,不允许使用 value 和 writable 这两个属性。

  • get:一个给属性提供 getter 的方法,默认值为 undefined
  • set:一个给属性提供 setter 的方法。默认值为 undefined,该方法接受唯一的参数,并将该参数的新值分配给该属性
let obj = {};
let temp = 'bjl';
Object.defineProperty(obj, 'name', {
    get: function() {
        return temp
    },
    set: function(val) {
        temp = val
    }
})
console.log(obj.name)  // bjl
// 当修改属性时,就会触发方法里的set方法
obj.name = 'bao';
console.log(obj.name)  // bao

3. enumerable:表示目标属性是否可以被枚举

有时我们会对对象进行遍历,只有被枚举的属性可以被遍历到,如下所示:

  • for...in...
let obj = {
    name: 'bjl',
    age: 18
}
Object.defineProperty(obj, 'sex', {
    value: '女'
})
for(let key in obj) {
    console.log(key)  // name age
}
  • Object.keys()
let obj = {
    name: 'bjl',
    age: 18
}
Object.defineProperty(obj, 'sex', {
    value: '女'
})
console.log(Object.keys(obj))  // ['name', 'age']
Object.keys(obj).map(key => {
    console.log(key)  // name age
})

我们可以看出,使用 Object.defineProperty() 添加的属性不能被枚举到,也就是不能被遍历到。Object.keys() 返回的是可以被枚举到的数组,所以打印结果如上所述。

添加 enumerable 描述属性可以改变,如下所示:

let obj = {
    name: 'bjl',
    age: 18
}
Object.defineProperty(obj, 'sex', {
    value: '女',
    enumerable: true
})
console.log(Object.keys(obj))  // ['name', 'age', 'sex']
Object.keys(obj).map(key => {
    console.log(key)  // name age sex
})

4. configurable:目标属性是否可以被删除或是否可以再次修改特性

  • 对象原属性默认为 true,可以被删除
let obj = {
    name: 'bjl',
    age: 18
}
delete obj.name;
console.log(obj)  // {age: 18}
  • Object.defineProperty() 内部属性为 false,不可被删除
let obj = {
    name: 'bjl',
    age: 18
}
Object.defineProperty(obj, 'sex', {
    value: '女'
})
delete obj.sex;
console.log(obj)  // {name: 'bjl', age: 18, sex: '女'}
  • 使用 configurable 属性设置可以删除属性
let obj = {
    name: 'bjl',
    age: 18
}
Object.defineProperty(obj, 'sex', {
    value: '女',
    configurable: true
})
Object.defineProperty(obj, 'name', {
    configurable: true
})
delete obj.sex;
delete obj.name;
console.log(obj)  // {age: 18}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值