JavaScript 原始值:存储在栈中的简单数据段。也叫基本数据类型,包括 Number、Stirng、Boolean、Null、Underfined。
let s1 = 'some text';
typeof s1 // "string"
let s2 = s1.substring(2);
显然,s1 是一个基础数据类型,不是一个对象,所以按道理说,s1 是不应该有 substring (或者其他任何属性和方法)方法的。但是字符串是有这个方法的。那是因为每当用到原始值的某个属性和方法时,后台都会创建一个相应的原始包装对象,从而暴露出操作原始值的各种方法。
具体来说,当以上代码第二行访问 s1 时,是以读写模式访问的,也就是要从内存中读取变量保存的值。在以读写模式访问字符串值的时候,后台都会执行 3 步操作:
let s1 = new String('some text');
let s2 = s1.substring(2);
s1 = null;
- 创建一个原始值的实例
- 调用这个实例上的方法
- 销毁这个实例
这种行为让原始值拥有对象的行为。
let str = 'abc';
str.color = 'red';
console.log(str.color); // undefined
解读:在非严格模式下,当我们尝试给原始值赋值时,其实是生成了一个原始值包装类型实例,也是给这个新生成的实例赋值,但是在赋值之后这个实例就被销毁了。实际上并没有将值赋值我们想要的目标变量身上,其次,在下次读取这个属性,又创建了一个原始值包装类型实例,显然这个实例(对象)和之前那个赋值的不是同一个实例,所以自然读取不到属性值。
引用类型和包装类型的主要区别在于生命周期
- 通过 new 实例化引用类型后,得到的实例会在离开作用于时被销毁
- 而自动创建的原始值包装对象只存在于访问它的那行代码执行期间
- 这意味着不能运行时给原始值添加属性和方法
显示的创建原始值包装类型
let s1 = new String('some text');
typeof s1 // "object"
s1.color = 'red';
console.log(s1.color); // red
包装类型是特殊的引用类型。每当读取一个基本类型值的时候,后台就会创建一个对应的基本包装类型的对象,从而可能调用一些方法来操作这些数据,此行代码运行完被创建的对象即被销毁。
包装类型共包括 Boolean、Number 和 String 三种。