19-对象
3.12 对象
对象跟不可变的基本类型不太一样,基本类型只能代表一个值,而对象可以代表多个值或者复杂的值,而且这个值在其生命周期内都是可变的。本质上,对象是一个容器,容器的内容可以随着时间推移而改变(也就是同一个对象拥有不同的内容)。跟基本类型一样,对象也有自己语法:大括号({ })。因为大括号是成对出现的,所以可以在大括号内填充对象的内容。下面从一个空对象开始:
const obj = {};
可以给对象任意命名,通常建议取一个表意的名字,比如,user或 `shoppingCart` 。这里只是为了学习对象的原理,例子中的对象没有任何特殊的意义,所以就简单称之为 `obj` 。
对象的内容称作属性(或成员),属性是由名称(或键)和值组成。属性名必须是字符串或者符号,值可以是任意类型(包括其他对象)。接下来给 obj 添加一个 color 属性:
obj.size; // undefined
obj.color; // "yellow"
为了使用成员访问运算符,属性名必须是一个合法的标识符。如果想使用非法的标识符作为属性名,必须使用计算机成员访问符(它对合法的标识符也起作用):
obj["not an identifier"] = 3;
obj["not an identifier"]; // 3
obj["color"]; // "yellow"
也可以使用计算机成员访问操作符来访问符号属性:
const SIZE = Symbol();
obj[SIZE] = 8;
obj[SIZE]; // 8
上面例子中,obj有三个属性,它们的键(key)分别是 "color" (合法的字符串标识符), "not an identifier" (不合法的字符串标识符), SIZE (符号)。
如果读者在使用JavaScript控制台,可能会注意到控制台不会将 `SIZE` 符号当作 `obj` 的属性列出来。的确(可以输入 `obj[SIZE]` 来验证),符号属性的处理方式会有些不同,一般默认是不显示的。其次要注意,符号属性的键是符号 `SIZE` ,而不是字符串 `"SIZE"` 。为了证明这一点,可以输入 `obj.SIZE = 0` (成员访问操作符始终作用于字符串属性),然后输入 `obj[SIZE]` 和 `obj.SIZE` (或者 `obj["SIZE"]` )。
现在,回忆一下基本类型和对象的区别。本节中,一直在操作和修改变量obj所包含的对象,但是 obj 始终指向同一个对象。假如 obj 被字符串或数字或者任意其他基本类型取代,每一次改变的时候它将变成一个不同的值。换言之, obj 自始至终指向同一个对象,只是对象自身的内容被修改了。
在 obj 的例子中,创建了一个空对象,对象的语法还允许创建包含初始属性的对象。在大括号内部,属性用逗号间隔,属性名和属性值用冒号隔开。
const sam1 = {
name: 'Sam',
age: 4,
};
const sam2 = { name: 'Sam', age: 4 }; // 在同一行声明
const sam3 = {
name: 'Sam',
classification: { //属性值也可以是对象
kingdom: 'Anamalia',
phylum: 'Chordata',
class: 'Mamalia',
order: 'Carnivoria',
family: 'Felidae',
subfaimily: 'Felinae',
genus: 'Felis',
species: 'catus',
},
};
这个例子中,又创建了三个对象来展示对象字面量语法。注意, sam1 和 sam2 包含的属性是一样的,然而,它们却是两个不同的对象(再一次拿基本类型做比较:两个包含数字3的基本类型变量有相同的引用)。对象 sam3 的 classification 属性本身就是一个对象。考虑一下访问 sam3 中classification的属性family的不同方式(无所谓使用单引号、双引号还是重音符):
sam3.classification.family; // "Felinae"
sam3["classification"].family; // "Felinae"
sam3.classification["family"]; // "Felinae"
sam3["classification"]["family"]; // "Felinae"
对象还可以包含函数。第6章会深入学习函数。但现在,只需要知道函数内部包含了代码(实质上是子程序)。来看看如何给 sam3 添加一个函数:
sam3.speak = function() { return "Meow!"; };
现在可以使用方法名+括号的方式调用它:
sam3.speak(); // "Meow!"
最后,可以通过delete操作来删除对象中的属性:
delete sam3.classification; // 整个classification树被移除
delete sam3.speak; // speak函数被移除
如果熟悉面向对象编程(OOP),可能想知道JavaScript对象是如何跟OOP关联起来的。现在,可以先将对象看成是一般的容器,后面会在第9章再详细讨论OOP。
可以给对象任意命名,通常建议取一个表意的名字,比如,user或 `shoppingCart` 。这里只是为了学习对象的原理,例子中的对象没有任何特殊的意义,所以就简单称之为 `obj` 。