跳到主要内容

6. 集合引用类型

Object

到目前为止,大多数引用值的示例使用的是Object类型。Object是ECMAScript中最常用的类型之一。虽然Object的实例没有多少功能,但很适合存储和在应用程序间交换数据。

显式地创建Object的实例有两种方式。第一种是使用new操作符和Object构造函数,如下所示:

    let person = new Object();
person.name = "Nicholas";
person.age = 29;

另一种方式是使用对象字面量(object literal)表示法。对象字面量是对象定义的简写形式,目的是为了简化包含大量属性的对象的创建。比如,下面的代码定义了与前面示例相同的person对象,但使用的是对象字面量表示法:

    let person = {
name: "Nicholas",
age: 29
};

在这个例子中,左大括号({)表示对象字面量开始,因为它出现在一个表达式上下文(expression context)中。在ECMAScript中,表达式上下文指的是期待返回值的上下文。赋值操作符表示后面要期待一个值,因此左大括号表示一个表达式的开始。同样是左大括号,如果出现在语句上下文(statement context)中,比如if语句的条件后面,则表示一个语句块的开始。

接下来指定了name属性,后跟一个冒号,然后是属性的值。逗号用于在对象字面量中分隔属性,因此字符串"Nicholas"后面有一个逗号,而29后面没有,因为age是这个对象的最后一个属性。在最后一个属性后面加上逗号在非常老的浏览器中会导致报错,但所有现代浏览器都支持这种写法。

在对象字面量表示法中,属性名可以是字符串或数值,比如:

    let person = {
"name": "Nicholas",
"age": 29,
5: true
};

这个例子会得到一个带有属性name、age和5的对象。注意,数值属性会自动转换为字符串。

当然也可以用对象字面量表示法来定义一个只有默认属性和方法的对象,只要使用一对大括号,中间留空就行了:

    let person={};//与newObject()相同
person.name = "Nicholas";
person.age = 29;

这个例子跟本节开始的第一个例子是等效的,虽然看起来有点怪。对象字面量表示法通常只在为了让属性一目了然时才使用。

注意 在使用对象字面量表示法定义对象时,并不会实际调用Object构造函数。

虽然使用哪种方式创建Object实例都可以,但实际上开发者更倾向于使用对象字面量表示法。这是因为对象字面量代码更少,看起来也更有封装所有相关数据的感觉。事实上,对象字面量已经成为给函数传递大量可选参数的主要方式,比如:

    function displayInfo(args) {
let output = "";
if (typeof args.name == "string"){
output += "Name: " + args.name + "\n";
}
if (typeof args.age == "number") {
output += "Age: " + args.age + "\n";
}
alert(output);
}
displayInfo({
name: "Nicholas",
age: 29
});
displayInfo({
name: "Greg"
});

这里,函数displayInfo()接收一个名为args的参数。这个参数可能有属性name或age,也可能两个属性都有或者都没有。函数内部会使用typeof操作符测试每个属性是否存在,然后根据属性有无构造并显示一条消息。然后,这个函数被调用了两次,每次都通过一个对象字面量传入了不同的数据。两种情况下,函数都正常运行。

注意 这种模式非常适合函数有大量可选参数的情况。一般来说,命名参数更直观,但在可选参数过多的时候就显得笨拙了。最好的方式是对必选参数使用命名参数,再通过一个对象字面量来封装多个可选参数。

虽然属性一般是通过点语法来存取的,这也是面向对象语言的惯例,但也可以使用中括号来存取属性。在使用中括号时,要在括号内使用属性名的字符串形式,比如:

    console.log(person["name"]); // "Nicholas"
console.log(person.name); // "Nicholas"

从功能上讲,这两种存取属性的方式没有区别。使用中括号的主要优势就是可以通过变量访问属性,就像下面这个例子中一样:

    let propertyName = "name";
console.log(person[propertyName]); // "Nicholas"

Array

定型数组

Map

WeakMap

Set

WeakSet

迭代与扩展操作

小结

JavaScript中的对象是引用值,可以通过几种内置引用类型创建特定类型的对象。

  • 引用类型与传统面向对象编程语言中的类相似,但实现不同。
  • Object类型是一个基础类型,所有引用类型都从它继承了基本的行为。
  • Array类型表示一组有序的值,并提供了操作和转换值的能力。
  • 定型数组包含一套不同的引用类型,用于管理数值在内存中的类型。
  • Date类型提供了关于日期和时间的信息,包括当前日期和时间以及计算。
  • RegExp类型是ECMAScript支持的正则表达式的接口,提供了大多数基本正则表达式以及一些高级正则表达式的能力。

JavaScript比较独特的一点是,函数其实是Function类型的实例,这意味着函数也是对象。由于函数是对象,因此也就具有能够增强自身行为的方法。

因为原始值包装类型的存在,所以JavaScript中的原始值可以拥有类似对象的行为。有3种原始值包装类型:Boolean、Number和String。它们都具有如下特点。

  • 每种包装类型都映射到同名的原始类型。
  • 在以读模式访问原始值时,后台会实例化一个原始值包装对象,通过这个对象可以操作数据。
  • 涉及原始值的语句只要一执行完毕,包装对象就会立即销毁。

JavaScript还有两个在一开始执行代码时就存在的内置对象:Global和Math。其中,Global对象在大多数ECMAScript实现中无法直接访问。不过浏览器将Global实现为window对象。所有全局变量和函数都是Global对象的属性。Math对象包含辅助完成复杂数学计算的属性和方法。

ECMAScript 6新增了一批引用类型:Map、WeakMap、Set和WeakSet。这些类型为组织应用程序数据和简化内存管理提供了新能力。