5.8 属性的访问
生成的对象可以通过属性来访问。对于对象的引用可以使用点运算符(.)或中括号运算符([])来访问其属性。需要注意的是,在点运算符之后书写的属性名会被认为是标识符,而中括号运算符内的则是被转为字符串值的式子。请看下面的例子:
var hzh1 = { x:3, y:4 };
console.log("输出hzh对象的x属性:");
console.log("hzh1.x = " + hzh1.x); // 属性x
console.log("hzh1[x] = " + hzh1['x']); // 属性x
var hzh2 = 'x';
console.log("hzh1[hzh2] = " + hzh1[hzh2]); // 属性x(而非属性key)
[Running] node "e:\HMV\JavaScript\JavaScript.js"
输出hzh对象的x属性:
hzh1.x = 3
hzh1[x] = 3
hzh1[hzh2] = 3
[Done] exited with code=0 in 0.181 seconds
不过,对于对象字面量的属性名来说,下面这样的标识符或字符字面量形式的表示,都没问题。请注意不要与上面的规则混淆。
var hzh1 = 'x';
var hzh2 = { hzh1:3 }; // 属性hzh1(而非属性x)
var hzh2 = { 'x':3 }; // 属性x
这里需要多提一句,属性访问的运算对象并不是变量,而是对象的引用。这一点,可以从以下直接 对对象字面量进行运算的示例中得到确认:
console.log("确认属性访问的运算对象是对象的引用:");
console.log({x:3, y:4}.x); // 属性x
console.log({x:3, y:4}['x']); // 属性x
[Running] node "e:\HMV\JavaScript\JavaScript.js"
确认属性访问的运算对象是对象的引用:
3
3
[Done] exited with code=0 in 0.183 seconds
现实中几乎不会对对象字面量进行运算。不过当这种运算对象不是一个变量时,倒是常常会以方法链之类的形式出现。
5.8.1 属性值的更新
在赋值表达式的左侧书写属性访问表达式能够实现对属性值的改写。如果指定的是不存在的属性名,则会新增该属性。下面将不再使用右侧或左侧的说法,而改用属性读取,以及属性写入这样的术语。
可以使用 delete 运算表达式来删除属性。这里需要注意的是,很难区分不存在的属性与属性值为undefined 值的属性。
5.8.2 点运算符与中括号运算符在使用上的区别
有时选择用于访问对象属性的这两个运算符只凭偏好。点运算符的表述较为简洁,所以通常都会选用点运算符。不过,中括号运算符的通用性更高。
能使用点运算符的情况一定也可以使用中括号运算符,反之未必成立。但也无需因此全都使用中括号运算符。通常默认使用表述简洁的点运算符,只有在不得不使用中括号运算符的情况下,才使用中括号运算符。
只能使用中括号运算符的情况分为以下几种。
- 使用了不能作为标识符的属性名的情况。
- 将变量的值作为属性名使用的情况。
- 将表达式的求值结果作为属性名使用的情况。
包含数值或横杠(-)的字符串不能作为标识符使用。无法作为标识符使用的字符串,不能用于点运算符的属性名,且对于保留字,也有这样的限制。不过,原本就不应该将保留字作为属性名使用,所以这里不再赘述。
像下面这样,将含有横杠的属性名用于点运算符会引起错误。
// 含有横杠的属性名
var hzh = { 'huang-zihan':5 };
console.log(hzh.huang-zihan); // 将解释为hzh.huang减去zihan,从而造成错误
[Running] node "e:\HMV\JavaScript\JavaScript.js"
e:\HMV\JavaScript\JavaScript.js:3
console.log(hzh.huang-zihan); // 将解释为hzh.huang减去zihan,从而造成错误
^
ReferenceError: zihan is not defined
at Object.<anonymous> (e:\HMV\JavaScript\JavaScript.js:3:23)
at Module._compile (internal/modules/cjs/loader.js:999:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
at Module.load (internal/modules/cjs/loader.js:863:32)
at Function.Module._load (internal/modules/cjs/loader.js:708:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12)
at internal/main/run_main_module.js:17:47
[Done] exited with code=1 in 0.413 seconds
无法作为标识符被使用的字符串,仍可以在中括号运算符中使用。请看下面的例子,其中以字符串值指定了一个属性名。
// 含有横杠的属性名
var hzh = { 'huang-zihan':5 };
console.log(hzh['huang-zihan']); // 使用[]运算以字符串值指定了一个属性名。可以正常执行
[Running] node "e:\HMV\JavaScript\JavaScript.js"
5
[Done] exited with code=0 in 0.773 seconds
数值也是如此。数组对象的属性名都是数值。由于点运算符无法使用数值,因此只能使用中括号运算符。而且很多程序设计语言都是通过中括号运算符来访问数组的元素,所以可读性也随之提高。
下面的例子仍使用了之前的代码,用于展示将被变量的值作为属性名使用的情况。
var hzh1 = { x:3, y:4 };
console.log("输出hzh对象的x属性:");
console.log("hzh1.x = " + hzh1.x); // 属性x
console.log("hzh1[x] = " + hzh1['x']); // 属性x
var hzh2 = 'x';
console.log("hzh1[hzh2] = " + hzh1[hzh2]); // 属性x(而非属性key)
[Running] node "e:\HMV\JavaScript\JavaScript.js"
输出hzh对象的x属性:
hzh1.x = 3
hzh1[x] = 3
hzh1[hzh2] = 3
[Done] exited with code=0 in 0.181 seconds
如果表达式的求值结果是字符串,可以直接用中括号运算符通过该表达式指定属性名。下面引用出自《JavaScript 语言精粹》一书的一个具有一定技巧性的例子。
这段代码会根据数值的符号而选择调用不同的方法。方法调用一词会让人觉得要使用的是点运算符,不过事实上中括号运算符也能被调用。
// 引用自《JavaScript语言精粹》一书
// 仅读取数值的整数部分的处理
Math[this < 0 ? 'ceiling' : 'floor'](this));
5.8.3 属性的枚举
可以通过 for in 语句对属性名进行枚举(代码清单 5.10)。通过在 for in 语句中使用中括号运算符,可以间接地实现对属性值的枚举。使用 for each in 语句可以直接枚举属性值。
代码清单 5.10 属性的枚举
var hzh1 = { x:'黄子涵是帅哥!', y:'黄子涵是靓仔!', z:'黄子涵真聪明!' };
for(var key in hzh1) {
console.log('key = ', key); // 属性名的枚举
console.log('val = ', hzh1[key]); // 属性值的枚举
}
[Running] node "e:\HMV\JavaScript\JavaScript.js"
key = x
val = 黄子涵是帅哥!
key = y
val = 黄子涵是靓仔!
key = z
val = 黄子涵真聪明!
[Done] exited with code=0 in 0.262 seconds
属性可以分为直接属性以及继承于原型的属性。for in 语句和 for each in 语句都会枚举继承于原型的属性。