Object.defineProperty

89 阅读2分钟

1. 简介

Object.defineProperty()  静态方法会直接在一个对象上定义一个新属性,或修改其现有属性,并返回此对象。

2. 用法

Object.defineProperty(obj, prop, descriptor)
  • obj: 要操作的对象
  • prop: 要定义或修改的属性键
  • descriptor: 要定义或修改的属性的描述符
    • value: 属性的值
    • writable:属性的值是否可写 如果是true,则可以被重写,否则就是只读
    • configurable: 是否可配置
    • enumerable:是否可枚举
    • get: 当获取该属性值时触发get方法,返回值为该属性值
    • set:当设置该属性值时触发set方法,参数为设置的属性值。

描述符中[value, writable]和[get, set]不能同时出现。

value = 1;
Object.defineProperty(obj, 'test', {
    get(){
        return value * 2;
    },
    set(newVal){
        value = value * 2;
    }
})
obj.test // 2
obj.test = 2
obj.test // 4

3. obj.key = value

obj1 = {a: 1};
obj1.b = 2;
console.log(obj1); // {a: 1, b: 2}
obj2 = {a: 1};
Object.defineProperty(obj2, 'b', {value: 2});
console.log(obj2); // {a: 1, b: 2}

以上两种方式有什么异同?

image.png 通过Object.getOwnPropertyDescriptors可以看到,在writable enumerable configurable这三个描述符的属性上,

  • Object.key方式赋值,以上三个属性默认为true
  • defineProperty方式默认为false

4. writable

当 writable 特性设置为 false 时,该属性不可写,不能被重新赋值。

尝试对一个不可写的属性进行写入不会改变它,在严格模式下会导致错误。

obj = {}
Object.defineProperty(obj, 'a', {
  value: 1,
  writable: false,
  configurable: true,
  enumerable: true
})
obj.a = 2
console.log(obj) // {a: 1}

可以看到,对属性a赋值无效

5. configurable

configurable 特性控制属性是否可以从对象中删除以及其特性(除了 value 和 writable)是否可以更改。

  • 不影响valuewritable
  • 可支持 writable 修改一次,从 true 改为 false
  • writable为false时,value也无法修改了
Object.defineProperty(obj, "key", {
  value: 1,
  writable: true,
  configurable: false, // 不可配置
  enumerable: true,
});

修改描述符,会报错

Object.defineProperty(obj, 'key', {
  value: 2,
  writable: false,
  configurable: false,
  enumerable: false
})
// Uncaught TypeError: Cannot redefine property: key
// at Function.defineProperty (<anonymous>)

可以修改writable为false,但无法再修改为true

Object.defineProperty(obj, 'key', {
  writable: false,
}) // 成功

6. enumerable

设置该属性是否可枚举

obj = {test : 1};
Object.defineProperty(obj, 'key', {
  value: 2,
  writable: true,
  configurable: true,
  enumerable: false // 设置enumerable为false, 则该属性就不可以被枚举了
})
console.log(obj); // {test: 1, key: 2}
  • Object.keys()
Object.keys(obj) // ['test']
  • for...in
for(item in obj){
    console.log(item);
}
// test

7. getter / setter

value 与 getter / setter 不可同时出现。

value = 1;
Object.defineProperty(obj, 'test', {
    get(){
        return value * 2;
    },
    set(newVal){
        value = value * 2;
    }
})
obj.test // 2
obj.test = 2
obj.test // 4
  • 第一次调用getter,返回 1 * 2 的结果,为 2
  • 第一次调用setter,更新value值,为 1 * 2 = 2
  • 第二次调用getter,返回 2 * 2 的结果,为 4