JavaScript 中的对象类型

  |   0 评论   |   0 浏览

什么是对象

简单的说,对象就是一组属性(property)的集合。每个属性包含两部分:

  • 属性名(key)—— 可以是字符串或者符号(symbol)类型值。
  • 特征(attributes)—— 用来描述属性的状态。

属性的分类

对象属性可以分为两类:

  • 数据属性(data property)—— 属性值是可以直接访问的。
  • 访问器属性(accessor property)—— 属性值通过访问器函数(accessor function)来访问的,包含gettersetter 方法。getter方法用来获取属性值,setter 方法用来设置属性值。换句话说,访问器属性不单独保存属性值,属性值都是通过访问器函数来获取和设置的。

一个属性要么是访问器属性(具有 getter/setter 方法),要么是数据属性(具有 value),但不能两者都是。

示例:

 1let user = {
 2  // name 和 surname 是数据属性
 3  name: "John",
 4  surname: "Smith",
 5  // fullname 是访问器属性,定义 getter 和 setter 方法不需要使用 function 关键字
 6  get fullName() {
 7    return `${this.name} ${this.surname}`;
 8  },
 9
10  set fullName(value) {
11    [this.name, this.surname] = value.split(" ");
12  }
13};
14user.name; // John
15user.fullName; // John Smith

属性的特征

数据属性中的特征:

Attribute Name Value Domain Description
[[Value]] 属性值。
[[Writable]] Boolean 若是true,则可以修改属性值,否则属性值不可修改。
[[Enumerable]] Boolean 若是true,则可以使用 for-in枚举该属性值,否则该属性值不可枚举。
[[Configurable]] Boolean 若是true,则该属性可被删除,可被修改为访问器属性,或者可以修改该属性的部分特征(不能修改[[Value]],不能将[[Writable]]修改为 false

访问器属性中的特征:

Attribute Name Value Domain Description
[[Get]] Object or Undefined 若属性值是对象,则必须是函数对象。该函数用来获取属性值。
[[Set]] Object or Undefined 若属性值是对象,则必须是函数对象。该函数用来修改属性值。
[[Enumerable]] Boolean 若是true,则可以使用 for-in枚举该属性值,否则该属性值不可枚举。
[[Configurable]] Boolean 若是true,则该属性可被删除,可被修改为数据属性,或者可以修改该属性的特征。

用来描述属性的特征(attribute)是存放在属性描述对象(attributes object)中的,这些特征又被称为属性描述符

通过 Object.getOwnPropertyDescriptor()方法可以获取对象属性的属性描述对象

1var obj = { p: 'a' };
2
3Object.getOwnPropertyDescriptor(obj, 'p');
4// { value: "a",
5//   writable: true,
6//   enumerable: true,
7//   configurable: true
8//   __proto__: Object
9// }

对象的创建

对象的创建有三种方式:

  • 使用初始化器 —— 对象字面量。
  • 使用构造函数 —— 使用new关键字让构造函数返回一个对象实例。
  • 使用Object.create()方法 —— 以现有对象为原型,返回一个新的对象。

初始化器

一个对象初始化器,由大括号 ({}) 和其包含的零个或多个键值对构成。

示例一: ES6 之前的语法

1var o = {}; // 这是一个空对象
2var o = {a: 'foo', b: 42, c: {}};

**示例二:**ES6 新增的语法

 1// 属性可以用变量
 2var a = 'foo', b = 42, c = {};
 3var o = {a, b, c};
 4
 5// 若属性值是函数,可省略 function 关键字
 6const o = {
 7  method() {
 8    return "Hello!";
 9  }
10};
11// 等同于
12const o = {
13  method: function() {
14    return "Hello!";
15  }
16};
17
18// 属性名可以使用变量和表达式
19var prop = 'foo';
20var o = {
21  [prop]: 'hey',
22  ['b' + 'ar']: 'there'
23};

构造函数

在早期,JavaScript 语言使用构造函数(constructor)作为创建对象的模板。构造函数与普通函数的区别是:函数体内部使用了 this关键字表示所要生成的对象实例,生成对象时必须使用 new关键字。

 1function Point(x, y) {
 2  this.x = x;
 3  this.y = y;
 4}
 5
 6Point.prototype.toString = function () {
 7  return '(' + this.x + ', ' + this.y + ')';
 8};
 9
10var p = new Point(1, 2);

这种写法跟传统的面向对象语言(例如 C++ 和 Java)差异很大,让学过 Java 等语言的人感到困惑和费解。后来,ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class关键字,可以定义类。ES6 的 class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到。

 1class Point {
 2  // 构造器
 3  constructor(x, y) {
 4    this.x = x;
 5    this.y = y;
 6  }
 7
 8  toString() {
 9    return '(' + this.x + ', ' + this.y + ')';
10  }
11}

Object.create()方法

以现有的对象作为原型,生成新的实例对象。新生成的对象会继承原型对象的属性。

 1// 原型对象
 2var A = {
 3  print: function () {
 4    console.log('hello');
 5  }
 6};
 7
 8// 实例对象
 9var B = Object.create(A);
10
11Object.getPrototypeOf(B) === A // true
12B.print() // hello
13B.print === A.print // true

Object.create()方法生成的对象,会继承它的原型对象的构造函数。

1function A() {}
2var a = new A();
3var b = Object.create(a);
4
5b.constructor === A // true
6b instanceof A // true

属性的操作

属性的查看

使用 Object.keys方法查看一个对象本身的所有属性。

1var obj = {
2  key1: 1,
3  key2: 2
4};
5
6Object.keys(obj);
7// ['key1', 'key2']

属性的读取

读取对象的属性,有两种方法,一种是使用点运算符,还有一种是使用方括号运算符。

1var obj = {
2  p: 'Hello World'
3};
4
5obj.p // "Hello World"
6obj['p'] // "Hello World"

方括号运算符中可以使用变量和表达式。

1var foo = 'bar';
2
3var obj = {
4  foo: 1,
5  bar: 2
6};
7
8obj.foo  // 1
9obj[foo]  // 2

属性的新增和修改

与属性的读取一样,可以使用点运算符或者方括号运算符,来新增或者修改属性。若指定的属性存在,则修改该属性的值;若不存在,则新增该属性。

1var obj = {};
2// JavaScript 允许属性的“后绑定”,也就是说,你可以在任意时刻新增属性,没必要在定义对象的时候,就定义好属性。
3obj.foo = 'Hello';
4obj['bar'] = 'World';

这种方法只能设置属性的值,属性的其他特征都是默认值。

若要对对象属性进行更精细的设置,则可以使用 Object.defineProperty()方法来新增或修改属性。它的用法如下:

1Object.defineProperty(object, propertyName, attributesObject)

Object.defineProperty方法接受三个参数:

  • object:属性所在的对象
  • propertyName:字符串,表示属性名
  • attributesObject:属性描述对象

若属性不存在,则新增该属性;若属性存在,则更新该属性。该方法的返回值是修改后的对象。

 1var obj = Object.defineProperty({}, 'p', {
 2  value: 123,
 3  writable: false, // 将属性设置为不可修改
 4  enumerable: true,
 5  configurable: false
 6});
 7
 8obj.p // 123
 9
10obj.p = 246;
11obj.p // 123

属性的删除

delete命令用于删除对象的属性,删除成功后返回 true

1var obj = { p: 1 };
2Object.keys(obj) // ["p"]
3
4delete obj.p // true
5obj.p // undefined
6Object.keys(obj) // []

相关资料

6.1.7 The Object Type
数据类型-对象
标准库-属性描述对象
JavaScript 标准内置对象-Object
Class 的基本语法