原始类型的自动转换

课后整理 2020-12-20

原始类型的值,可以自动当作对象调用,即调用各种对象的方法和参数。这时,JavaScript引擎会自动将原始类型的值转为包装对象,在使用后立刻销毁。

例如,字符串可以调用length属性,返回字符串的长度。

'abc'.length // 3

在上面代码中,abc是一个字符串,本身不是对象,不能调用length属性。JavaScript引擎自动将其转为包装对象,在这个对象上调用length属性。调用结束后,这个临时对象就会被销毁。这就叫原始类型的自动转换。例如:

var str = 'abc';
str.length // 3
// 等同于 
var strObj = new String(str)
// String {
//   0: "a", 1:  "b", 2: "c", length: 3, [[PrimitiveValue]]: "abc"
// }
strObj.length // 3

在上面代码中,字符串abc的包装对象有每个位置的值、有length属性、还有一个内部属性[[PrimitiveValue]]保存字符串的原始值。这个[[PrimitiveValue]]内部属性,外部是无法调用,仅供valueOf或toString这样的方法内部调用。

这个临时对象是只读的,无法修改。所以,字符串无法添加新属性。例如:

var s = 'Hello World';
s.x = 123;
s.x // undefined

上面代码为字符串s添加了一个x属性,结果无效,总是返回undefined。

另一方面,调用结束后,临时对象会自动销毁。这意味着,下一次调用字符串的属性时,实际是调用一个新生成的对象,而不是上一次调用时生成的那个对象,所以取不到赋值在上一个对象的属性。如果想要为字符串添加属性,只有在它的原型对象String.prototype上定义。

这种原始类型值可以直接调用的方法还有很多,除了前面介绍过的valueOf和toString方法,还包括三个包装对象各自定义在原型上的方法。例如:

'abc'.charAt === String.prototype.charAt                   //  true

上面代码表示,字符串abc的charAt方法,实际上就是定义在String对象原型上的方法。

如果包装对象与原始类型值进行混合运算,包装对象会转化为原始类型。例如:

new Number(123) + 123 // 246
new String('abc') + 'abc' // "abcabc"