JS对象之属性描述符

135 阅读3分钟

属性描述符

这里就不说怎么去创建对象,取和修改对象的值这些了。从ES5开始,所有的对象都具备了属性描述符,

      let person = {
	 name:"陈志元"
	};

      Object.defineProperty(person, "name", {
        configurable: true,
        writable: true,
        enumerable: true, 
        value: "陈志元",
      });

如你所见,这个普通的对象属性对应的属性描述符,可不仅仅只是一个"丁时一",它还包含另外三个特性configurable,writable,enumerable

writable

writable决定是否可以修改。

      let person = {};

      Object.defineProperty(person, "name", {
        configurable: true,
        writable: true, 
        enumerable: true,
        value: "陈志元",
      });

      console.log(person.name); //陈志元
      person.name = "帅哥"; 
      console.log(person.name); //帅哥

将writable修改为false后

      "use strict";
      let person = {};

      Object.defineProperty(person, "name", {
        configurable: true,
        writable: false, //不可写!
        enumerable: true,
        value: "陈志元",
      });

      console.log(person.name); //陈志元
      person.name = "帅哥"; //在模式下 Cannot assign to read only property "name" of object "#<Object>"
      console.log(person.name); //陈志元

在非严格模式下,修改会静默失败,但在严格模式下,就会抛出TypeError错误!

configurable

configurable表示属性是否可配置。只要属性是可配置的,就可以使用Object.defineProperty来修改属性描述符。

      let myobj={
        a:3
      }
      
      myobj.a=4
      console.log(myobj.a);//4

      Object.defineProperty(myobj,"a",{
        configurable:false,//不可配置!
        writable:true,
        value:4
      })
      myobj.a=5
      console.log(myobj.a);//5

      Object.defineProperty(myobj, "a", {
        configurable: true,
        writable: true,
      });//TypeError

最后一个Object.defineProperty会产生一个TypeError,不管是否处于严格模式,尝试修改一个不可配置的属性描述符都会发生错误,所以把configurable设置为false是单向操作!

补充

在《JavaScript高级程序设计》(第四版)中有提到:一个属性被定义为不可配置之后,再次调用Object.defineProperty()并修改除writable以外的属性都会导致错误

这里我提一下,在configurable为false的情况下,还是可以把writable从true改为false,但是由false改为true就会导致错误!

由true变false

 let person = {};

      Object.defineProperty(person, "name", {
        configurable: false,
        writable: true,
        enumerable: true,
        value: "陈志元",
      });
      console.log(person); // {name: "陈志元"}
      person.name = "丁青年";
      console.log(person); //{name: "丁丁"}

      //现在尝试把writeable修改为false
      //没有报错
      Object.defineProperty(person, "name", {
        configurable: false,
        writable: false,
        value: "啦啦啦",
      });
      console.log(person); //{name: "啦啦啦""}

由false变true

      let person = {};

      Object.defineProperty(person, "name", {
        configurable: false,
        writable: false,
        enumerable: true,
        value: "陈志元",
      });

 //现在尝试把writeable改为true
      //报错 Cannot redefine property: name at Function.defineProperty (<anonymous>)
      Object.defineProperty(person, "name", {
        configurable: false,
        writable: true,
        value: "啦啦啦",
      });

并且除了无法修改,configurable:false还会禁用删除这个属性

      const obj={
        name:"丁时一"
      }

      delete obj.name
      console.log(obj);//{} 属性被删除

      Object.defineProperty(obj,"name",{
        configurable:false,
        value:"丁时一"
      })

      delete obj.name

      console.log(obj);//{name: "丁时一"}

enumerable

控制属性是否会出现在对象的枚举当中,比如说for…in循环,如果enumerable为false那么这个属性就不会出现在枚举当中

  let person = {};

      Object.defineProperty(person, "name", {
        configurable: true,
        writable: true,
        enumerable: true, //可枚举
        value: "陈志元",
      });
      Object.defineProperty(person, "age", {
        configurable: true,
        writable: true,
        enumerable: false, //不可枚举
        value: 20,
      });

      console.log(person); //{name: "陈志元", age: 20}
      for (let i in person) {
        //并没有age  因为age不可枚举
        console.log(i, person[i]); //name 陈志元
      }

结尾

在调用Object.defineProperty()时,如果这三个参数都不指定,那么全部默认为false,我们可以使用 Object.defineProperties给对象同时定义多个属性

      const obj = {};
      Object.defineProperties(obj, {
        name: {
          value: "陈志元",
        },
        age: {
          value: 20,
        },
      });

      obj.name="帅哥"
      console.log(obj.name);//陈志元 writable默认false

      for(let i in obj){
        console.log(i);//没有打印 enumerable默认false
      }

      Object.defineProperty(obj,"name",{
        configurable:true
      })//TypeError 因为我们正在尝试修改一个不可配置属性

这里我们定义了一个不可枚举属性age,虽然能够正常的访问它,但是并没有出现在枚举当中。

今天就到这里啦~如果有什么不足的地方,希望各位看官评论区提醒哦AwA