对象属性描述对象-JavaScript

2024-10-10 23:15:44

一、定义

属性描述对象是 ECMAScript 5 新增的语法,它其实就是一个内部对象,用来描述对象的属性的特性。每个属性都有自己对应的属性描述对象,用来描述该属性的信息,以及控制它的行为。

属性描述对象提供6个属性描述:

1. value

表示属性的值,默认为undefined,可以是任何类型值。

2. writable

boolean类型,表示该属性值是否可以被修改,默认是true,如果是false,表示不能修改属性值。

3. enumerable

enumerable是一个布尔值类型,表示该属性是否可以被遍历,默认是true。如果是false,会使某些操作(比如for in 、Object.keys)跳过遍历。

4. configurable

configurable是一个布尔值,表示可配置性,默认为true。其为true时,表示该属性可以被删除,也可以修改属性描述对象。如果为false,表示不能删除该属性,也不得改变该属性的属性描述对象。

5. get

是一个函数,用于获取属性的值。当访问该属性时,会调用该函数并返回其返回值。默认是undefined。

6. set

是一个函数,用于设置属性的值。当访问该属性时,会调用该函数并返回其返回值。默认是undefined。

二、示例

1. value

表示属性值,通过这个属性,可以获取和设置属性的值。

const obj = {};
obj.name = "xiaoming";

Object.getOwnPropertyDescriptor(obj, "name").value;  // xiaoming
Object.defineProperty(obj, "name", { value: "xiaoli" });  // {name: “xiaoli”} 
obj.name // xiaoli

2. writable

该属性是一个布尔值类型,表示是否可以修改属性值。

const obj = {};
obj.name = "xiaoming";

Object.getOwnPropertyDescriptor(obj, "name").value;  // xiaoming
Object.defineProperty(obj, "name", { writable: false });  // {name: “xiaoming”} 
obj.name = "xiaoli"; // 修改name值
obj.name; // xiaoming 返回的name值还是之前的,并不是最新赋值的

需注意,在正常模式下,直接目标属性赋值(obj.name = "xiaoli"),对writable为false(configurable是否为false、true无关)的属性赋值不会报错,只会默默失败。但是,严格模式下会报错,即使对name属性重新赋予一个同样的值。

"use strict";
const obj = {};
obj.name = "xiaoming";

Object.getOwnPropertyDescriptor(obj, "name").value;  // xiaoming
Object.defineProperty(obj, "name", { writable: false });  // {name: “xiaoming”} 
obj.name = "xiaoming";
// TypeError: Cannot assign to read only property “name” of object

3. enumerable

该属性是一个布尔值类型,表示是否可以通过for in 或者 Object.keys()进行遍历,如果是false,遍历时,跳过该属性。

const obj = {};
obj.name = "xiaoming";
obj.age = 18;

Object.getOwnPropertyDescriptor(obj, "name").enumerable; // true 可枚举
for(let key in obj) {
  console.log(key); // name age
}

// 设置enumerable为false
Object.defineProperty(obj, "name", { enumerable: false });
Object.getOwnPropertyDescriptor(obj, "name").enumerable; // false 不可枚举
for(let key in obj) {
  console.log(key); // age
}

4. configurable

该属性是一个布尔值类型,表示可配置性,有两方面作用:

  1. 是否可修改属性描述对象
  2. 是否可删除目标属性

(1)是否可修改属性描述对象

如果configurable为false,value、enumerable、writable和configurable禁止修改,但需要注意的有两点:

  1. 当configurable为false时,writable为false时,其值修改为true会报错,但是如果writable为true时,其值修改为false是允许的。
  2. 对于value,只要writable和configurable有一个为true,就允许改动。

如果configurable为false,value、enumerable、writable和configurable修改值时,会报错:

const obj = Object.defineProperty({}, "name", {
  value: "xiaoming",
  writable: false,
  enumerable: false,
  configurable: false
});

Object.defineProperty(obj, "name", { value: "xiaoli" });
// TypeError: Cannot redefine property: name

Object.defineProperty(obj, "name", { writable: true });
// TypeError: Cannot redefine property: name

Object.defineProperty(obj, "name", { enumerable: true });
// TypeError: Cannot redefine property: name

Object.defineProperty(obj, "name", { configurable: true });
// TypeError: Cannot redefine property: name

但是如果你设置的值和当前属性描述对象的值一致时,并不会报错。

const obj = Object.defineProperty({}, "name", {
  value: "xiaoming",
  writable: false,
  enumerable: false,
  configurable: false
});

Object.defineProperty(obj, "name", { configurable: false });
Object.defineProperty(obj, "name", { value: "xiaoming" });
Object.defineProperty(obj, "name", { writable: false });
Object.defineProperty(obj, "name", { enumerable: false });
// 以上都不报错

当configurable为false时,writable为false时,其值修改为true会报错,但是如果writable为true时,其值修改为false是允许的。

const obj = Object.defineProperty({}, "name", {
  value: "xiaoming",
  writable: true,
  enumerable: false,
  configurable: false
});
Object.defineProperty(obj, "name", { writable: false }); // 修改成功

const obj2 = Object.defineProperty({}, "name", {
  value: "xiaoming",
  writable: false,
  enumerable: false,
  configurable: false
});
Object.defineProperty(obj2, "name", { writable: true });
// TypeError: Cannot redefine property: name

对于value,只要writable和configurable有一个为true,就可以修改。

var obj = Object.defineProperty({}, "name", {
  value: "xiaoming",
  writable: true,
  configurable: false
});

Object.defineProperty(obj, "name" { value: "xiaoli" }); // 修改成功
obj.name; // xiaoli

var obj2 = Object.defineProperty({}, "name" {
  value: "xiaoming",
  writable: false,
  configurable: true
});

Object.defineProperty(obj2, "name", { value: "xiaoli" }); // 修改成功
obj2.name; // xiaoli

(2)是否可删除目标属性

configurable为false,禁止删除属性,如果为true时,可以删除属性。

const obj = Object.defineProperties({}, {
  name: { 
    value: "xiaoming",
    configurable: true
  },
  age: {
    value: 2,
    configurable: false
  }
});

delete obj.name // true,删除成功
obj.name // undefined

delete obj.age // false,删除失败,并不会报错
obj.age // 2

5. get 和set 函数

除了平时使用的点语法(obj.name)或者中括号语法(obj["name"])访问属性的 value 外,还可以使用访问器,包括 set 和 get 两个函数。

set 函数用来设置 value 值,get 函数用来读取 value 值。

举例说明一下:

const obj = Object.defineProperties({}, {
  _name: {
    value: "xiaoming",
    writable: true
  },
  name: {
    get() {
      return this._name;
    },
    set(value) {
      this._name = value; 
    }
  }
});
obj.name; // xiaoming
obj.name = "xiaoli";
obj.name; // xiaoli

第一次执行obj.name的时候,调用name的属性描述对象中的get函数,返回_name,即miaoxing。

当执行obj.name = "xiaoli"时,调用name的属性描述对象中的set函数,将_name赋值xiaoli,即此时_name的值是xiaoli。

第二次执行obj.name的时候,调用name的属性描述对象中的get函数,返回_name,即miaoli。

因此,此时返回的是xiaoli。

目录

相关推荐
JavaScript之 in 运算符及其应用浅析 URLSearchParams 使用深入理解JS函数去抖详细介绍JavaScript中的深拷贝、浅拷贝