JavaScript中的引用类型二(原始值包装类型)

145 阅读3分钟

原始值包装类型

为了方便操作原始值,ECMAScript 提供了3中特殊的引用类型:Boolean,Number和String。这些类型具有其他引用类型一样的特点,但也具有与各自原始类型对应的特殊行为,每当用到某个原始值的方法或属性时,后台都会创建一个相应原始包装类型,从而暴露出原始操作值的各种方法。

let s1 = "some text";
let s2 = s1.substring(2);

在这里,s1是一个包含字符串的变量,它是一个原始值。第二行紧接着在s1上调用了substring()方法,并把结果保存在s2中。我们知道,原始值本身不是对象,因此逻辑上不应该有方法,而实际上这个例子又确实按照预期运行了。这是因为后台做了很多处理,从而实现了上述操作。具体来说,当运行第二行s1时,是以读模式访问的,也就是要从内存中读取变量的值,在以读模式访问字符串值的任何时候,后台都会进行以下3步:

1)创建一个String类型的实例;
(2)调用实例上的特定方法;
(3)销毁实例。

可以把这3步想象成执行了如下3行ECMAScript 代码:

let s1 = new String("some text");
let s2 = s1.substring(2);
s1 = null;

这种行为可以让原始值拥有对象的行为。对布尔值和数值而言,以上3步也会在后台发生,只不过使用的是Boolean 和Number包装类型而已。
引用类型与原始值包装类型的主要区别在于对象的生命周期。在通过new 实例化引用类型后,得到的实例会在离开作用域时被销毁,而自动创建的原始值包装对象则只存在于访问它的那行代码执行期间。这意味着不能在运行时给原始值添加属性和方法。

let s1 = "some text";
s1.color = "red";
console.log(s1.color);

这里的第二行代码尝试给字符串s1添加一个color属性。可是第三行代码访问color属性时,它却不见了。原因就是第二行代码运行时会临时创建一个String对象,而当第三行代码执行时,这个对象已经销毁了。实际上,第三行代码在这里创建了自己的String对象,但这个对象没有color 属性
可以显示的使用Boolean,Number,String构造函数创建原始值包抓过对象。不过应该在确实必要时再这么做。否则容易让开发者疑惑,分不清楚到底是原始值还是引用值,在原始值包装类型的实例上掉哟个typeof会返回“object”,所有原始值包装对象都会转换为布尔值true。
另外,Object 构造函数作为一个工厂方法,能够根据传入值的类型返回相应原始值包装类型的实例。

let  obj = new Object("some text");
console.log(obj instanceof String);// true

如果给Object 的是字符串,则会创建一个String的实例。如果是数值,则会创建Number的实例。布尔值则会得到Boolean的实例。
注意,使用new 调用原始值包装类型的构造函数,与调用同名的转型函数并不一样。

let value = "25";
let number = Number(value);// 转型函数
console.log(typeof number);// "number"
let obj = new Number(value);// 构造函数
console.log(typeof obj); //"object"

在这个例子中,变量number 中保存的时一个值为25的原始数值,而变量obj中保存的时一个Number的实例。

虽然不推荐显示创建原始值包装类型的实例,但它们对于原始值的功能是很重要的。每个原始值包装类型都有一相应的一套方法来方便数据操作。