Object对象方法(八)defineProperty/defineProperties

86 阅读2分钟

javaScript Object对象方法defineProperty

作用:在一个对象上定义一个新属性,或者修改一个对象现有的属性,然后返回该对象

一、对象的描述符

1.1 configurable

当该对象的configurable=true的时候,该对象的描述符才能够被改变,属性也能删除。默认为false

1.2 enumerable

enumerable=true时,该属性才会出现在对象的枚举属性中,即:**console.log(对象)**的时候可不可见。

1.3 value

表示该属性对应的值,可以是任何有效的JavaScript

1.4 writable

writable=true,上面的value才能被赋值运算符改变。默认为false。

1.5 get

访问该对象对应的属性时进行拦截并且调用的函数

1.6 set

修改该对象对应的属性时进行拦截并且调用的函数

1.7 描述符分类

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

二、defineProperty使用场景

2.1 基本使用场景

const obj = {};
Object.defineProperty(obj, "key", {
  value: 10,
  writable: true,
  enumerable: true,
  configurable: true
});
obj.key = 12;
console.log(obj);
/* 结果
{
    "key": 12
}
*/

2.2 writable

Object.defineProperty(obj, "value", {
  value: "lucy",
  writable: false,
  enumerable: true,
  configurable: true
});
obj.value = "jam"; // 这行不生效,不可写,即:修改
console.log(obj);
/* 结果
{
  "key": 12,
  "value": "lucy"
}
*/

2.3 enumerable=false

Object.defineProperty(obj, "grade", {
  value: "A",
  writable: true,
  enumerable: false,
  configurable: true
});
console.log(obj);
for(let key in obj) {
  console.log(key);
}
/* 输出结果
  key
  value
  // 由于grade不可枚举,因此不会打印出来
*/
console.log(Object.keys(obj));
/* 输出结果
[
  "key",
  "value"
]
*/

2.4 configurable=false

const obj1 = {};
Object.defineProperty(obj1, "key", {
  value: "haha",
  configurable: false
});
Object.defineProperty(obj1, "key", {
  value: "haha",
  configurable: true
}); //直接报错
Object.defineProperty(obj1, "key", {
  value: "haha1",
  enumerable: true
}); //直接报错

2.5 自定义setters和getters

固定set、get值设置

const obj2 = {};
Object.defineProperty(obj2, "name", {
  get() {
    return "想获取名称?没门!";
  },
  set(val) {
    console.log(`想把名称该为${val}?没门!`);
  }
});
console.log(obj2.name); // 想获取名称?没门!
obj2.name = "古政"; // 想把名称该为古政?没门!

可变get、set设置。

const obj3 = {};
var value = 18;
Object.defineProperty(obj3, "age", {
  get() {
    return value;
  },
  set(newVal) {
    value = newVal;
  }
});
console.log(obj3.age); // 18
obj3.age = 22; // 修改成功
console.log(obj3.age); // 22

重点:可能会造成疑惑的写法

const obj4 = {
  age: 18
};
var value = obj4.age;
Object.defineProperty(obj4, "age", {
  get() {
    return value;
  },
  set(newVal) {
    value = newVal;
  }
});
console.log(obj4.age); // 18
obj4.age = 22; // 修改成功
console.log(obj4.age); // 22

笔者第一次学习手写Vue的双向绑定中,便遇到了以上的写法,当时一直想不明白,为什么set中修改了value后,可以直接修改掉obj4.age的内容?原理如下:

  • 第一步,console.log(obj4.age)时,会调用get方法获取到value
  • 第二步,obj4.age = 22后,value发生了改变,变为22
  • 第三步,console.log(obj4.age),注意!!这个时候并不是获取obj4中的age值,而是value的值
  • 总结:其实就是value做了一个闭包,使得后续的value值,服务于obj4对象中的age属性。 可以通过以下的图解,更好的了解。

image.png

二、defineProperties使用场景

作用:其实就是一个函数,定义多个属性,基本的内容以及原理与defineProperty相同。使用案例如下:

var obj = {};
Object.defineProperties(obj, {
  'property1': {
    value: true,
    writable: true
  },
  'property2': {
    value: 'Hello',
    writable: false
  }
});