我们经常会被问到一个问题: “ 谈谈你对 JavaScript 是弱类型语言的理解 ”
我们都知道 JavaScript 是弱类型语言,因为 JavaScript 声明变量的时候并没有预先确定类型,所以变量的类型就是其值的类型,也就是说:“变量当前的类型由它当前的值决定”。 所以在进行变量赋值的时候变量的值就可能变化了,这个变化的过程就发生了强制类型转换。
所以重点来啦!
强制类型转换的规则
在 JavaScript 发生类型转换的时候,其实是将操作的对象转化为原始对象。这个时候就必定会调用到 ToPrimitive 方法。
ToPrimitive 方法对原始类型不发生转换处理,只针对引用类型(Object),该方法的目的就是将引用类型转换为非引用类型,即原始类型。
ToPrimitive 的语法如下:
/**
* obj 需要进行转换的对象
* type 期望转换成为的原始数据类型,可选
*/
ToPrimitive(obj, type);
这里就会出现几种当 Type 的值不同的时候,其内置转换的不同过程
- Type 为 String
- 先调用 obj 的 toString 方法,如果为原始值,则 return,否则进行第 2 步
- 调用 obj的valueOf 方法,如果为原始值,则 return ,否则进行第 3 步
- 抛出 TypeError 异常
- Type 为 Number
- 先调用 obj 的 valueOf 方法,如果为原始值,则 return ,否则进行第 2 步
- 调用 obj 的 toString 方法,如果为原始值, 则 return ,否则第 3 步
- 抛出 TypeError 异常
- Type 为 空
- 如果该对象为 Date,则 type 被设置为 String
- 否则,type 被设置为 Number
关于 Date 类型的特殊说明:对于 Date 的数据类型,我们更多时候是希望得到时间后面的字符串,而非时间戳,如果是number的话,则取到的是对应的时间戳(毫秒值),但显然字符串是使用得更多的。
所以综上所述,ToPrimitive转换成哪种原始类型主要取决于type,如果指定则按照指定类型转换,如果不指定的话分为两种情况:Date类型的为String,其余对象为number。那么问题来了,什么时候会指定type的类型呢?那就要看上面提到的两种转换方式了:toString和valueOf,我们要知道的是,toString()和valueOf()在特定的场合下会自行调用。
-
toString()
该方法返回一个表示该对象的字符串,每个对象都有一个toString()方法,当对象被表示为文本值或者当以期望字符串的方式引用对象时,该方法被自动调用。
-
valueOf()
该方法返回指定对象的原始值。JavaScript调用valueOf()方法用来把对象转换成原始类型的值,这个方法一般也是被自动调用的。不同内置对象的valueOf实现如下:
- String.valueOf() => 返回字符串值
- Number.valueOf() => 返回数字值
- Date.valueOf() => 返回数字,即时间值(毫秒级时间戳)
- Boolean.valueOf() => 返回Boolean的this值
- Object.valueOf() => 返回this
Number
- null => 0
- undefined => NaN
- true => 1,false => 0
- 字符串转换遵循数字常量规则,转换失败返回NaN
- 对象转换需要先转换为原始值,即为调用ToPrimitive转换,并指定 type 为number,然后继续回到ToPrimitive进行转换
String
- null => 'null'
- undefined => undefined
- true => ‘true’, false => ‘false'
- 数字转换遵循通用规则,极大极小的数字使用指定形式
- 对象转换同 number 的对象转换规则,区别是指定 type为string
🌰 如下:
String(null) // 'null'
String(undefined) // 'undefined'
String(true) // 'true'
String(1) // '1'
String(-1) // '-1'
String(0) // '0'
String(-0) // '0'
String(Math.pow(1000,10)) // '1e+30'
String(Infinity) // 'Infinity'
String(-Infinity) // '-Infinity'
String({}) // '[object Object]'
String([1,[2,3]]) // '1,2,3'
String(['Echo',1]) // 'Echo,1’
Boolean
Boolean 除了将下述 6 个值转换为 false ,其他的情况全部为 true
1. undefined
2. null
3. -0
4. 0 或 +0
5. NaN
6. '' (空字符串,有一个空格都不算空字符串)
上述假值意外以外的值都是真值,意思就是所有对象(包括空对象)的转换结果都是 true,并且连 false 对应的 bool 对象 new Boolean(false) 也是true。
🌰 如下:
Boolean(undefined) // false
Boolean(null) // false
Boolean(0) // false
Boolean(NaN) // false
Boolean('') // false
Boolean({}) // true
Boolean([]) // true
Boolean(new Boolean(false)) // true