let s1 = 'some text';
let s2 = s1.substring(2);
- 我们知道,原始值本身不是对象,因此字符串 s1 在逻辑上不应该有 substring() 方法。
- 而实际上,大家都知道字符串有这个方法。
- 这是因为每当用到某个原始值的方法或属性时,后台都会创建一个相应原始包装的对象,从而暴露出操作原始值的各种方法。
- 具体来说,当第二行访问s1 时,是以读写模式访问的,也就是要从内存中读取变量保存的值。
- 在以读写模式访问字符串值的任何时候,后台都会执行以下3步:
- 创建一个String 类型的实例。
- 调用实例上的特定方法。
- 销毁实例。 - 可以把这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); // undefined
- 原因就是第二行代码运行会临时创建一个 String 对象,而当第三行代码执行时,这个对象已经被销毁了。
- 实际上,第三行代码在这里创建了自己的 String 对象,但这个对象没有 color 属性
显式地使用 Boolean、Number 和 String 构造函数创建原始值包装对象。
let s1 = new String('some text');
s1.color = 'red';
console.log(s1.color); // red
不推荐显式创建原始值包装类型的实例,否则容易让开发者迷惑,分不清它们到底是原始值还是引用值