红宝书 📒 5.3 基本引用类型-原始包装类型

175 阅读6分钟

「这是我参与11月更文挑战的第10天,活动详情查看:2021最后一次更文挑战

思考🤔 1

首先,思考一个问题:我们定义一个字符串,这个字符串是一个原始值,那么为什么我们可以对其使用方法呢?如下

let a = "ss"
let b = a.substring(2)   

答案是: ECMAScript 提供了三种特殊的引用类型 Boolean Number String。每当用到某个原始值的方法或属性时,后台都会创建一个相应原始包装类型的对象。

后台处理实际上经过了如下的过程:

let a = new String("ss")    //创建一个String类型实例
let b = a.substring(2)      // 调用实例上的方法
a = null                    // 销毁实例

思考🤔 2

给原始值添加属性可以吗?也就是定义一个字符串,能给字符串添加属性吗?

    let s = "some"   
    s.name = "test"   
    console.log(s.name)    //  undefined

第二行运行会创建一个String对象,但在第三行执行前,已经被销毁了。

第三行也创建了一个String对象,但是没有name属性。

思考🤔 3

原始包装类的typeof会是什么?

其实这个问题多余问,都是引用类型了。执行typeof 一定是object类型。

看两行代码

let string = new String("ss")
typeof string    //  object
if(string){
    console.log(11)
}                          // 11

打印了11,说明什么?说明if(string)括号内的条件是true。所有的原始包装类都会转换为布尔值true。

Boolean(string)  //true

因为Object构造函数作为一个工厂方法,可以根据传入的类型返回相应的原始包装类型(下面是用instanceof 检测具体的引用类型,因为typeof对于引用类型的检测都是object,当然除了函数)

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

类型转换

let value = "24"
let number = Number(value)

而如果在前面加一个new关键字,就是构造函数了。

let obj = new Number("24")
typeof obj            //object

5.3.1 Boolean

重写了valueOf(),返回原始数据类型。toString()返回字符串

创建

传入true或false。当然你传入字符串:"true","false"也是可以的,因为他自己会处理。

let bool = new Boolean(true)
let bool1 = new Boolean(false)     

很少使用

Boolean对象在ECMAScript中很少使用。

let booleanObj = new Boolean(false)
let result = booleanObj && true         // 前面说过Boolean对象都会转为true
console.log(result)                     // true

一般这种情况下我们都是声明原始值的boolean类型

let falseValue = false
let result = falseValue && true
console.log(result)                // false

5.3.2 Number

重写了valueOf()、toLocalString()、toString()方法。

  • valueOf():返回对象的原始值
  • toString():不传参数返回字符串、参数传 2 8 10 16 分别对应二进制、八进制、十进制、十六进制。
  • toLocalString():返回字符串

其他方法 之所以原始类型能使用方法,是因为原始包装类型

toFixed()

返回指定小数点位数的数值字符串

let num = 10
console.log(num.toFixed(2))   // "10.00"

如果小数的位数大于 指定的小数位数,则四舍五入

let num = 10.005
console.log(num.toFixed(2))   // "10.01"

对了,这里提一下 一个特殊的求和,好像是计算机二进制上的问题。所有语言执行都会这样

0.1+0.2 = 0.30000000000000004

toExponential()

返回科学计数法表示的数值字符串。参数表示结果中的小数的位数。

一般来说,这么小的数不会使用科学计数法

let num =10
num.toExponential()        // "1.0e+1"

toPrecision()

根据情况返回最合理的输出结果

let num = 99; 
console.log(num.toPrecision(1)); // "1e+2" 
console.log(num.toPrecision(2)); // "99" 
console.log(num.toPrecision(3)); // "99.0"

isInteger()

ES6新增,用于检测是否是整数。有时候,1.00也会被认为是浮点数

console.log(Number.isInteger(1))     // true
console.log(Number.isInteger(1.0))   // true
console.log(Number.isInteger(1.01))   // false

5.3.3 String

3个继承的方法

valueOf()、toLocaleString()和 toString()都返回对象的原始字符串值。

length属性

字符串都具有length属性

let str = "hello"
str.length            // "5"

charAt()

找到指定位置的字符

let str = "hello"
console.log(charAt(2))    "l"

charCodeAt()

查看指定码元的字符编码。Unicode码

"A".charCodeAt()    //65

我觉得不是很常用。

concat()

用于将一个或多个字符串拼接成一个新字符串,可以接收多个参数。但我们常用的拼接方式都是用 + 加号

let a1 ="bro"
let a2 ="ther"
let a3 = a1.concat(a2,"!")   // 'brother!'

let a4 = a1 + a2 

slice() substr() substring()

都是截取字符串的方法

两个参数

  • 第一个:截取开始位置
  • 第二个:截取结束位置 非必要 不包括这个位置的字符
let str = "hello world"
str.slice(3)       // "lo world"
str.substring(3)   // "lo world"
str.substr(3)      // "lo world"

str.slice(3,7)     // "lo w"   不包括7位置上的o
str.substring(3,7) // "lo w"
str.substr(3,7)    // "lo w"

当参数是负数,就不同了

str.slice(-3)   // "rld"    从右侧开始 是-1
str.substr(-3)  // "rld"    第一个负参数当成字符串长度+这个值  11 +(-3)= 8  相当于 str.substr(8)
str.substring(-3)  // "hello world"   负数被替换为0

str.slice(3,-4)   // "lo w"    
str.substr(3,-4)   // ""            第二个负参数转为0   (3,0)所以是空
str.substring(3,-4)  // "hello world"   

字符串位置方法

  • indexOf():字符第一次出现的位置
  • lastIndexOf():字符第二次出现的位置 如果字符串中不含有此字符,则返回-1
let str = "hello world"
str.indexOf("o")        // 4
str.lastIndexOf("o")    // 7

还有可选的第二个参数

let str = "hello world"
str.indexOf("o",6)        // 7
str.lastIndexOf("o",6)    // 4

结果恰好反过来了。indexOf从索引为6的位置开始向后搜索,lastIndexOf从索引为6的位置向前搜索。

字符串包含方法

ES6新增

  • startsWith():是否以传入字符串为起始
  • endsWith():是否以传入字符串为结束
  • includes():是否包含传入字符串
let str ="start"
str.startsWith("s")      // true
str.startsWith("a")      // false
str.includes("s")        // true
str.includes("srt")      // false

startsWith() 和 endsWith() 有第二个参数。

去空格

  • trim() 会创建字符串的一个副本,删除前、后所有空格,再返回结果。
  • trimLeft() 从字符串开始去空格
  • trimRight() 从字符串末尾去空格

repeat()

参数是重复出现次数

let a ="cat"
a.repeat(5)    // catcatcatcatcat

padStart()和 padEnd()

两个参数:第一个参数:新字符串的长度,第二个参数:补位的字符

let a = "cat"
a.padStart(6,"!")   // '!!!cat'   以补位字符开始
a.padStart(6)       // '   cat'   不传第二个参数就是空格

a.padEnd(6,"!")     // 'cat!!!'   以补位字符结束
a.padEnd(6)         // 'cat   '

a.padStart(3)        // 'cat'    等于原字符串长度就相当于复制
a.padStart(2)        // 'cat'    小于原字符串长度相当于复制

字符串迭代与解构

字符串的原型上暴露了一个@@iterator,表示可以迭代字符串的每个字符。

let a = "cat"
let itera = a[Symbol.iterator]
console.log(itera.next())   // {value: 'c', done: false}
console.log(itera.next())   // {value: 'a', done: false}
console.log(itera.next())   // {value: 't', done: false}
console.log(itera.next())   // {value: undefined, done: true}   done:true 结束了

解构也是因为这个迭代器才可以实现的

let a ="cat"
console.log([...a])  // ['c', 'a', 't']

大小写转换

地区特定方法和通用方法一样。如不知道代码涉及什么语言,最好使用Local的

let world = "Hello World"
world.toLocaleLowerCase()   // 'hello world'
world.toLowerCase()          // 'hello world'

world.toLocaleUpperCase()   // 'HELLO WORLD'
world.toUpperCase()          //'HELLO WORLD'