前言
我们都知道,JS
数据类型分为两种:基本类型(原始类型)和引用类型
。
基本类型的值是保存在栈内存中的简单数据段,他们是按值访问的。JS
有6中基本类型:Undefined、Null、Boolean、Number、String、Symbol
。
引用类型的值是保存在堆内存中的对象,它的值是按引用访问的。引用类型主要有:Object、Array、Function、RegExp、Date
。
对象类型
对象是拥有属性和方法的,如下:
const people = ['小黄','小红']
people.push('小蓝')
people.length // 3
Array
是引用类型,所以它自然拥有属性和方法。但是,当我们声明一个字符串,可以调用substring
方法,这是为什么呢?
const word = 'you are the best'
const subWord = word.substring(0, 7) // "you are"
string
是基本类型,为什么可以拥有方法呢?这一切,都是因为有个叫"基本包装类型
"的东西。
基本包装类型
除了一开始提到的Object、Array
等引用类型,JavaScript
还为我们提供了三种特殊的引用类型:String
、Number
和Boolean
,方便我们操作对应的基本类型。
上面的word
尽管使用了substring
方法,word
本身的值是不会变的,调用这个方法只是返回了一个新的字符串。这就是基本包装类型的作用了。本来你是没有方法的,但是你想用方法的时候,你尽管调,对应的基本包装类型有这个方法就行。例如上面的substring
方法,string
这个基本类型是不可能有这个方法的,但是String
这个包装类型有,它会把这个方法执行完把结果返回。在执行到下面这行代码的时候,发生了很多事情:
word.substring(0, 7)
首先,他会从内存中读取word
的值,当处于这种读取模式下的时候,后台就开始干活了。JS高级程序设计
是这样描述后台完成的这些动作的:
- 创建
String
类型的一个实例 - 在实例上调用指定的方法
- 销毁这个实例
上面的代码可以解释为:
const _word = new String('you are the best')
const subWord = _word.substring(0, 7) // "you are"
_word = null // 方法调用后立即卸载
所以,这样我们就明白了,并不是基本类型string
执行了自身方法,而是后台为它创建了一个对应的基本包装类型String
,它根据基本类型的值实例化出了一个实例,让这个实例去调用指定方法,最后销毁自己。
由于基本包装类型“会销毁
”的特性,这决定了我们不能为基本类型值添加自定义属性和方法
。
const word = 'you are the best'
word.name= 'john'
console.log(word.age) //undefined
我们给word添加了name属性,然而,再次访问时,这个属性无法访问到,这是因为:执行到第二行代码属性赋值时,后台创建了一个基本包装类型的实例,这个属性确实挂到实例上了,但是紧接着,这个实例就被销毁了,执行到第三行时,又重新创建了新的基本包装类型的实例,就没有name属性了。
显示使用基本包装类型
除了在字符串处于读取模式下,后台会帮助我们创建基本包装类型实例,我们也可以自己显式地创建。
const _word = new String('you are the best')
const subWord = _word.substring(0, 7) // "you are"
在控制台打印,效果如下:
但是,这样和后台帮我们创建对象时变量中保存的东西是不同的。
const word = 'you are the best'
const _word = new String('you are the best')
typeof word // 'string'
typeof _word // 'object'
总结
有了基本包装类型,使我们操作string、boolean、number
这三种基本类型更方便了。在读取这三种基本类型值时,后台会创建对应的包装类型实例,这个实例会调用指定方法,调用完会被销毁。这种短暂的生命周期也决定了我们不能为基本类型添加自定义的属性和方法。