数据类型 | 原始值包装类型
红宝书第四版P113:为了方便操作原始值,ECMAScript 提供了3 种特殊的引用类型:Boolean、Number 和String
装箱和拆箱
- 装箱:将基本数据类型转换为对应的引用数据类型(分为隐式装箱和显式装箱)
- 隐式装箱:当读取一个基本类型值时,后台会创建一个该基本类型所对应的基本包装类型对象
- 显式装箱:通过
new 包装类型
的方式进行转换
- 拆箱:将引用数据类型转换为基本数据类型
看下面这个例子:
1 | var s1 = 'someText'; // 后台偷偷操作了,隐式! |
分析:
s1
是一个保存字符串的变量,是一个原始值,在第二行调用了调用了substring()
方法,并把结果保存在s2
中。原始值本身不是一个对象,照理说不应该有方法,但是事实确实调用方法成功了。实际上,当第二行访问s1
时,是以读模式访问的,也就是要从内存中读取变量保存的值。在以读模式访问字符串值的任何时候,后台都会执行以下3 步:
- 创建一个String 类型的实例;
- 调用实例上的特定方法
- 销毁实例
以上3步可抽象为下列代码:
1 | var s1 = new String('someText'); // new 了, 显式! |
从上面的例子我们不难看出:
引用类型与原始值包装类型的主要区别在于对象的生命周期
具体来说:在通过new 实例化引用类型后,得到的实例会在离开作用域时被销毁,而自动创建的原始值包装对象则只存在于访问它的那行代码执行期间,这意味着不能在运行时给原始值添加属性和方法
1 | let s1 = "some text"; |
创建原始值包装类型【装箱】的方式有:
- 显式地使用Boolean、Number 和String 构造函数创建原始值包装对象
- Object 构造函数作为一个工厂方法,能够根据传入值的类型返回相应原始值包装类型的实例
1 | let obj = new Object("some text"); |
需要注意的是:使用new 调用原始值包装类型的构造函数,与调用同名的转型函数并不一样(注意区分转型函数和构造函数)
1 | let value = "25"; |
Boolean
Boolean 是对应布尔值的引用类型
创建Boolean对象
1 | let booleanObject = new Boolean(true); |
Boolean实例的变化
Boolean实例重写
valueOf()
方法,返回一个原始值true
或者false
,toString()
方法被调用时也会被覆盖,返回字符串''true''
或者''false''
看下面这个例子:
1 | let falseObject = new Boolean(false); // 包装了一个值为false的Boolean对象 |
Boolean对象与原始布尔值的区别
- typeof返回不一样
1 | let falseObject = new Boolean(false); |
- instanceof检测不一样
1 | let falseObject = new Boolean(false); |
Number
Number 是对应数值的引用类型
创建Number对象
1 | let numberObject = new Number(10); |
Number实例的变化
Number实例重写
valueOf()
方法,toString()
方法和toLocaleString()
方法
valueOf()
方法返回Number
对象表示的原始数值,另外两个方法返回数值字符串
toString()
方法可选地接收一个表示基数的参数,并返回相应基数形式的数值字符串
1 | let num = 10; |
Number类型新方法
数值格式化为字符串
toFix()
toFixed()
方法返回包含指定小数点位数的数值字符串,接受一个参数表示小数位数
1 | let num = 10; |
toExponential()
toExponential()
,返回以科学记数法(也称为指数记数法)表示的数值字符串,接受一个参数表示小数位数
toPrecision()
toPrecision()
方法会根据情况返回最合理的输出结果,可能是固定长度,也可能是科学记数法形式这个方法接收一个参数,表示结果中数字的总位数(不包含指数)
isInteger()
ES6
新增了Number.isInteger()
方法,用于辨别一个数值是否保存为整数
.isSafeInteger()
IEEE 754 数值格式有一个特殊的数值范围,在这个范围内二进制值可以表示一个整数值。这个数值范围从Number.MIN_SAFE_INTEGER(-2^53 + 1)到Number.MAX_SAFE_INTEGER(2^53 - 1)。对超出这个范围的数值,即使尝试保存为整数,IEEE 754 编码格式也意味着二进制值可能会表示一个完全不同的数值。为了鉴别整数是否在这个范围内,可以使用Number.isSafeInteger()方法
Number对象与原始数值的区别
- typeof返回不一样
1 | let numberObject = new Number(10); |
- instanceof检测不一样
1 | let numberObject = new Number(10); |
String
String 是对应字符串的引用类型
创建String对象
1 | let stringObject = new String('hello world'); |
String实例
String
对象的方法可以在所有字符串原始值上调用- 3 个继承的方法
valueOf()
、toLocaleString()
和toString()
都返回对象的原始字符串值 - 每个
String
对象都有一个length
属性,表示字符串中字符的数
String类型方法
JavaScript字符
- length:表示字符串中字符的数量
- charAt():返回给定索引位置的字符,由传给方法的整数参数指定
1 | let message = "abcde"; |
- charCodeAt(): 可以查看指定码元的字符编码,这个方法返回指定索引位置的码元值,索引以整数指定
1 | let message = "abcde"; |
- fromCharCode(): 用于根据给定的UTF-16 码元创建字符串中的字符。这个方法可以接受任意多个数值,并返回将所有数值对应的字符拼接起来的字符串
1 | // Unicode "Latin small letter A"的编码是U+0061 |
- codePointAt(): codePointAt()接收16 位码元的索引并返回该索引位置上的码点(code point)。码点是Unicode 中一个字符的完整标识
1 | let message = "ab☺de"; |
- fromCodePoint(): 方法接收任意数量的码点,返回对应字符拼接起来的字符串
1 | console.log(String.fromCharCode(97, 98, 55357, 56842, 100, 101)); // ab☺de |
字符串规范化方法
- normalize(): 通过比较字符串与其调用normalize()的返回值,就可以知道该字符串是否已经规范化
字符串拼接方法
- concat(): 用于将一个或多个字符串拼接成一个新字符串,不改变原字符串
1 | let stringValue = "hello "; |
- 加号操作符(+): 当加号操作符有一方为字符串时,则执行字符串拼接
字符串提取方法
- slice()
- substr()
- substring()
字符串位置方法
- indexOf()
- lastIndexOf()
这两个方法从字符串中搜索传入的字符串,并返回位置,如果没找到,则返回-1
两者的区别在于,indexOf()方法从字符串开头开始查找子字符串,而lastIndexOf()方法从字符串末尾开始查找子字符串
1 | let stringValue = "hello world"; |
字符串包含方法
- startsWith()
- endsWith()
- includes()
这些方法都会从字符串中搜索传入的字符串,并返回一个表示是否包含的布尔值
区别在于,startsWith()
检查开始于索引0 的匹配项,endsWith()
检查开始于索引(string.length - substring.length)
的匹配项,而includes()
检查整个字符串
startsWith()和includes()方法接收可选的第二个参数,表示开始搜索的位置,如果传入第二个参数,则意味着这两个方法会从指定位置向着字符串末尾搜索,忽略该位置之前的所有字符
1 | let message = "foobarbaz"; |
字符串删除空格
- trim(): 这个方法会创建字符串的一个副本,删除前、后所有空格符,再返回结果,不影响原字符串
1 | let stringValue = " hello world "; |
- trimLeft()
- trimRight()
trimLeft()和trimRight()方法分别用于从字符串开始和末尾清理空格符
字符串重复方法
- repeat(): 这个方法接收一个整数参数,表示要将字符串复制多少次,然后返回拼接所有副本后的结果
1 | let stringValue = "na "; |
字符串填充方法
- padStart()
- padEnd()
这两个方法会复制字符串,如果小于指定长度,则在相应一边填充字符,直至满足长度条件
这两个方法的第一个参数是长度,第二个参数是可选的填充字符串,默认为空格
1 | let stringValue = "foo"; |
可选的第二个参数并不限于一个字符,如果提供了多个字符的字符串,则会将其拼接并截断以匹配指定长度
此外,如果长度小于或等于字符串长度,则会返回原始字符串
1 | let stringValue = "foo"; |
字符串迭代与解构
- @@iterator: 表示可以迭代字符串的每个字符
- for-of: 在for-of 循环中可以通过这个迭代器按序访问每个字符
- 解构操作符: 字符串可以通过解构操作符来解构
字符串大小转换
- toUpperCase()
- toLocaleLowerCase()
- toLowerCase()
- toLocaleUpperCase()
字符串模式匹配方法
- match(): 接收一个参数,可以是一个正则表达式字符串,也可以是一个RegExp 对象
1 | let text = "cat, bat, sat, fat"; |
- search(): 接收一个参数,可以是一个正则表达式字符串,也可以是一个RegExp 对象,返回模式第一个匹配的位置索引,如果没找到则返回1
1 | let text = "cat, bat, sat, fat"; |
- replace(): 方法接收两个参数,第一个参数可以是一个RegExp 对象或一个字符串(这个字符串不会转换为正则表达式),第二个参数可以是一个字符串或一个函数。如果第一个参数是字符串,那么只会替换第一个子字符串。要想替换所有子字符串,第一个参数必须为正则表达式并且带全局标记
1 | let text = "cat, bat, sat, fat"; |
- htmlEscape(): 将一段HTML 中的4 个字符替换成对应的实体:小于号、大于号、和号,还有双引号(都必须经过转义)
- split(): 会根据传入的分隔符将字符串拆分成数组
1 | let colorText = "red,blue,green,yellow"; |
字符串比较方法
- localeCompare(): 比较两个字符串,返回如下3 个值中的一个
- 如果按照字母表顺序,字符串应该排在字符串参数前头,则返回负值,一般为-1
- 如果字符串与字符串参数相等,则返回0
- 如果按照字母表顺序,字符串应该排在字符串参数后头,则返回正值,一般为1
1 | let stringValue = "yellow"; |