# 属性的描述符

在 JavaScript 中我们用属性来描述一个对象,同时属性也可以细分为两种:数据属性访问器属性。每种属性都带有自个的属性描述符,简单来说这些描述符就是属性的属性。

# 数据描述符

# configurable(可配置)

  • 默认值:false
  • 能否通过 delete 删除属性
  • 能否修改属性的描述符或者将属性改为访问器属性

# enumerable(可枚举)

  • 默认值:false
  • 能否通过 for-in 返回属性

# writable(可写入)

  • 默认值:false
  • 能否修改属性的值

# value(属性值)

  • 默认值:undefined
  • 属性的值

# 访问器描述符

访问器属性也带有 configurableenumerable ,除此之外,再加下面两个描述符

# get

  • 默认值:undefined
  • 读取属性时调用的函数

# set

  • 默认值:undefined
  • 给属性赋值时调用的函数

# 定义和获取属性描述符

# 定义属性描述符

# Object.defineProperty(obj, key, descriptor)

  • obj:属性所在对象
  • key:属性的名字
  • descriptor:属性的描述符对象

# Object.defineProperties(obj, props)

  • obj:属性所在对象
  • props:多个属性的描述符对象组成的对象

# 获取属性描述符

# Object.getOwnPropertyDescriptor(obj, key)

  • obj:属性所在对象
  • key:属性的名字

# 举个🌰

# 定义一个对象

var person = {
  name: 'randy'
}
1
2
3

对象 person 带有一个 name 属性,其值为 randy 。

# 获取属性描述符

console.log(Object.getOwnPropertyDescriptor(person, 'name'););
// 控制台打印如下:
{
  configurable: true,
  enumerable: true,
  writable: true,
  value: 'randy'
}
1
2
3
4
5
6
7
8

可以看出 name 属性默认是一个可配置、可枚举、可写入的数据属性。

# 修改属性描述符

# 不可配置

// 将 name 属性设置为不可配置
Object.defineProperty(person, 'name', {
  configurable: false
});
// 删除 name 属性
delete person.name
// 打印 name 属性,仍然存在
console.log(person.name); // randy
// 将 name 属性设置为可配置
// 此时会报错:不能重新定义 name 属性
Object.defineProperty(person, 'name', {
  configurable: true
});
1
2
3
4
5
6
7
8
9
10
11
12
13

将一个属性设置为不可配置后,该属性不能被删除也不能再次修改属性相关的描述符。

# 不可枚举

// 打印 person 所有属性
console.log(Object.keys(person)); // ['name']
// 将 name 属性设置为不可枚举
Object.defineProperty(person, 'name', {
  enumerable: false
});
// 打印 person 所有属性
console.log(Object.keys(person)); // []
1
2
3
4
5
6
7
8

Object.keys() 返回一个由对象自身带有属性组成的数组。第一次返回的数组中带有 name,而第二次返回空数组。

# 不可写入

// 修改 name 的值
person.name = 'Tony';
console.log(person.name); // Tony
// 将 name 属性设置为不可写入
Object.defineProperty(person, 'name', {
  writable: false
});
// 修改 name 的值
person.name = 'Randy';
console.log(person.name); // Tony
1
2
3
4
5
6
7
8
9
10

name 属性变为了只读属性

# 赋值操作

var person = {}
Object.defineProperty(person, 'name', {
  value: 'randy'
});
console.log(person.name); // randy
1
2
3
4
5

# 访问器属性

var num = 0;
Object.defineProperty(person, 'age', {
  get: function() {
    console.log('调用 age 属性的 getter 函数');
    return num;
  },
  set: function(newVal) {
    num = newVal;
    console.log('调用 age 属性的 setter 函数');
  }
});
person.age = 99; // 打印:调用 age 属性的 setter 函数
console.log(person.age); // 打印:调用 age 属性的 getter 函数
1
2
3
4
5
6
7
8
9
10
11
12
13

设置 age 属性的值会调用其 set 方法。
获取 age 属性的值会调用其 get 方法。