深入了解 Object.defineProperty

属性的操作

在 JavaScript 中,给对象增加一个属性是非常简单的,直接调用属性并赋值即可。

const obj = {
   };
obj.name = 'Tom';
console.log(obj);
/**
 * 输出:
 * {name: 'Tom'}
 */

通过这种方式添加的属性,可以随意操作:

  • 可修改
  • 可枚举
  • 可删除

可修改:

  // 可修改
+ obj.name = 'Jim';
+ console.log(obj.name);
  /**
  * 输出:
  * 'Jim'
  */

可枚举:

  // 可枚举
+ for (let key in obj) {
+   console.log(`${key} : ${obj[key]}`);
+ }
  /**
  * 输出:
  * name : Jim
  */

可删除:

  // 可删除
+ delete obj.name;
+ console.log(obj);
  /**
  * 输出:
  * {}
  */

如果想通过 Object.defineProperty 实现上面的功能,可以使用下面的代码:

- obj.name = 'Tom';
+ Object.defineProperty(obj, 'name', {
+   value: 'Tom',
+   writable: true,
+   enumerable: true,
+   configurable: true,
+ });

函数签名

在对 Object.defineProperty 深入学习之前,先对这个方法签名有一个认识:

Object.defineProperty(obj, prop, descriptor);

从函数签名中可以看出,definePropertyObject 上的一个静态方法,可以传递三个参数:

  • obj 要定义属性的对象
  • prop 要定义或修改的属性名称
  • descriptor 要定义或修改属性的描述符

返回值是被传递给函数的对象,也就是第一个参数 obj

描述符可以有以下几个可选值:

  • configurable
  • enumerable
  • value
  • writable
  • get
  • set

描述符

通过 Object.defineProperty 来为对象定义一个属性。

const obj = {
   };
Object.defineProperty(obj, 'name', {
   });
console.log(obj);
/**
 * 输出:
 * {name: undefined}
 */

从输出的结果可以看出,在对象 obj 上增加一个属性 name,但是它的值是 undefined

value

如果想给属性赋值,可以使用描述符中的 value 属性。

- Object.defineProperty(obj, 'name', {});
+ Object.defineProperty(obj, 'name', {
+   value: 'Tom',
+ });
  /**
  * 输出:
  * {name: 'Tom'}
  */

writable

一般情况下,修改一个对象中的属性值,可以使用 obj.name = 'Jim' 的形式。

+ obj.name = 'Jim';
+ console.log(obj);
  /**
  * 输出:
  * {name: 'Tom'}
  */

从输出结果可以看出,并没有修改成功。如果想修改属性值,可以把描述符中的 writable 设置为 true

  Object.defineProperty(obj, 'name', {
    value: 'Tom',
+   writable: true,
  });

enumerable

枚举对象的属性,可以使用 for...in

+ for (let key in obj) {
+   console.log(`${key} : ${obj[key]}`);
+ }

比较奇怪的是,执行上面的代码没有输出任何信息。

如果想正常枚举对象的属性,可以将描述符中的 enumerable 值设置为 true

  Object.defineProperty(obj, 'name', {
    value: 'Tom',
    writable: true,
+   enumerable: true,
  });

configurable

当这个属性不需要时,可以通过 delete 来删除。

+ delete obj.name;
+ console.log(obj);
  /**
  * 输出:
  * {name: 'Jim'}
  */

从输出结果可以看出,并没有达到预期的效果。如果想从对象上正常删除属性,可以将描述符中的 configurable 设置为 true

  Object.defineProperty(obj, 'name', {
    value: 'Tom',
    writable: true,
    enumerable: true,
+   configurable: true,
  });

get

如果需要获取对象的值,可以使用描述符中的 get

const obj = {
   };
let _tmpName = 'Tom';
Object.defineProperty(obj, 'name', {
   
  get() {
   
    return _tmpName;
  },
});
console.log(obj.name);
/**
 * 输出:
 * {name: 'Tom'}
 */

set

如果需要设置对象的值,可以使用描述符中的 set,它需要传递一个参数,就是修改后的值。

  Object.defineProperty(obj, 'name', {
    get() {
      return _tmpName;
    },
+   set(newVal) {
+     _tmpName = newVal;
+   },
  });

+ obj.name = 'Jim';
+ console.log(obj.name);
  /**
  * 输出:
  * {name: 'Jim'}
  */

注意事项

在操作符对象中,如果存在了 valuewritable 中的任意一个或多个,就不能存在 getset 了。

const obj = {
   };
Object.defineProperty(obj, 'name', {
   
  value: 1,
  get() {
   
    return 2;
  }

你可能感兴趣的:(javascript,defineProperty)