属性描述符

145 阅读5分钟

什么是属性描述符

无论使用字面量创建对象,还是通过new Object创建对象,或者通过类去创建对象都无法对对象的属性进行一些限制,比如是否可以被枚举,是否可以被delete删除,如果我们想对一个属性进行比较精准的控制,就需要使用到属性描述符。属性描述符需要使用Object.defineProperty来对象属性进行添加或者修改。

属性描述符分为两种:数据描述符(数据属性)和存取描述符(访问器属性)。

1. 数据描述符

数据描述符一般是指数据属性的描述符,一般我们所用到的属性都是数据属性,具有以下几种:

描述符说明
value该属性对应的值。
writable当且仅当该属性的writable为true时,value才能被赋值运算符改变。默认为false。
configurable当且仅当该属性的configurable为true时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除。默认为false。
enumerable当且仅当该属性的enumerable为true时,该属性才能够出现在对象的枚举属性中。默认为false。

2. 存取描述符

存取描述符一般为访问器属性的描述符,比如 getter函数和setter函数,具有以下几种:

描述符说明
get给属性提供getter的方法,如果没有getter则为undefined。当访问该属性时,该方法会被执行,方法执行时没有参数传入,但是会传入this对象
set给属性提供setter的方法,如果没有setter则为undefined。当属性值修改时,触发执行该方法。该方法将接受唯一参数,即该属性新的参数值。
configurable当且仅当该属性的configurable为true时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除。默认为false。
enumerable当且仅当该属性的enumerable为true时,该属性才能够出现在对象的枚举属性中。默认为false。

3. 获取属性描述符

我们可以通过Object.getOwnPropertyDescriptor()方法去获取属性描述符。

Object.getOwnPropertyDescriptor(obj,prop)

作用:获取目标对象身上目标属性的属性描述符。

参数:

  • obj:目标对象。
  • prop:目标属性。

返回值:目标属性的属性描述符。

    let person = {
      name: "于家宝",
      _age: 18,
    };
    console.log(Object.getOwnPropertyDescriptor(person, "_age"));

image.png

4. 设置属性描述符

我们可以通过 Object.defineProperty()方法去配置属性的描述符。

Object.defineProperty(obj,prop,descriptor)

作用:在目标对象上定义或者修改一个属性,同时可以配置该属性的属性描述符。

参数:

  • obj:目标对象。
  • prop:要定义或者修改的属性。
  • descriptor:是一个对象,存放着将要被配置的属性描述符。

返回值:目标对象。

    let person = {
      name: "于家宝",
    };
    Object.defineProperty(person, "job", {
      value: "程序员",
    });
    console.log(person.job); // 程序员

注意:如果通过Object.defineProperty()定义的属性,如果只设置了value一个属性描述符,那么该属性是不可删除、不可修改、不可枚举的。因为除了value属性描述符以外,其他的writableconfigurableenumerable默认都是false。

    let person = {
      name: "于家宝",
      age: 18,
    };
    Object.defineProperty(person, "job", {
      value: "程序员", // 不配置writable,configurable,enumerable就都默认false
    });
 
    console.log(person.job); // 程序员
    person.job = "前端工程师";
    delete person.job;
    console.log(person.job); // 程序员,不可修改不可删除
 
    for (i in person) {
      console.log(i); // name  age  没有job  不可枚举
    }

4.1 配置writable

配置writable为true以后该属性就可以修改了。

    let person = {
      name: "于家宝",
    };
    Object.defineProperty(person, "job", {
      value: "程序员",
      writable: true,
    });
    console.log(person.job); // 程序员
    person.job = "前端工程师";
    console.log(person.job); // 前端工程师

4.2 配置configurable

配置configurable为true以后该属性就可以修改了。

    let person = {
      name: "于家宝",
    };
    Object.defineProperty(person, "job", {
      value: "程序员",
      configurable: true,
    });
    console.log(person.job); // 程序员
    delete person.job;
    console.log(person.job); // undefined

注意:属性描述符configurable为true的时候,是可以修改该描述符configurable的,如果为false就无法修改该修饰符,这说明一旦configurable为false就是不可逆的。

举个例子:

先设置为true在改为false,属性不可以被删除。

    let person = {
      name: "于家宝",
    };
    Object.defineProperty(person, "job", {
      value: "程序员",
      configurable: true, // 先设置为true
    });
    Object.defineProperty(person, "job", {
      value: "程序员",
      configurable: false, // 再设置为false
    });
    console.log(person.job); // 程序员
    delete person.job;
    console.log(person.job); // 程序员  没有被删除,说明configurable修改为false成功了

先设置为false在改为true,后台报错。

    let person = {
      name: "于家宝",
    };
    Object.defineProperty(person, "job", {
      value: "程序员",
      configurable: false, // 先设置为false
    });
    Object.defineProperty(person, "job", {
      value: "程序员",
      configurable: true, // 再设置为true,直接报错,configurable为false的时候是不可以修改该属性描述符的
    });

image.png

4.3 配置enumerable

配置enumerable为true以后该属性就可以枚举了。

    let person = {
      name: "于家宝",
      age: 18,
    };
    Object.defineProperty(person, "job", {
      value: "程序员",
      enumerable: true,
    });
 
    for (i in person) {
      console.log(i); // name  age  job
    }

4.4 同时配置多个属性描述符

我们可以通过 Object.defineProperties()方法去设置属性的描述符。

Object.defineProperties(obj,props)

作用:在目标对象上定义或者修改一个或多个属性,可以同时配置属性的属性描述符。

参数:

  • obj:目标对象。
  • props:一个对象,每一个属性都是一个对象,键是要定义或者修改的属性,值是该属性的属性描述符。

返回值:目标对象。

    let person = {
      name: "于家宝",
      age: 18,
    };
    Object.defineProperties(person, {
      job: {
        value: "程序员",
        enumerable: true,
      },
      address: {
        value: "南京",
        enumerable: true,
      },
    });
 
    for (i in person) {
      console.log(i); // name  age  job  address
    }

4.5 get和set的用法具体去看getter和setter的帖子