JavaScript内置类型转换规则

218 阅读4分钟

我们经常会被问到一个问题: “ 谈谈你对 JavaScript 是弱类型语言的理解 ”

我们都知道 JavaScript 是弱类型语言,因为 JavaScript 声明变量的时候并没有预先确定类型,所以变量的类型就是其值的类型,也就是说:“变量当前的类型由它当前的值决定”。 所以在进行变量赋值的时候变量的值就可能变化了,这个变化的过程就发生了强制类型转换。

所以重点来啦!

强制类型转换的规则

在 JavaScript 发生类型转换的时候,其实是将操作的对象转化为原始对象。这个时候就必定会调用到 ToPrimitive 方法。

ToPrimitive 方法对原始类型不发生转换处理,只针对引用类型(Object),该方法的目的就是将引用类型转换为非引用类型,即原始类型。

ToPrimitive 的语法如下:

/**
* obj 需要进行转换的对象
* type 期望转换成为的原始数据类型,可选
*/
ToPrimitive(obj, type);

这里就会出现几种当 Type 的值不同的时候,其内置转换的不同过程

  • Type 为 String
    1. 先调用 obj 的 toString 方法,如果为原始值,则 return,否则进行第 2 步
    2. 调用 obj的valueOf 方法,如果为原始值,则 return ,否则进行第 3 步
    3. 抛出 TypeError 异常
  • Type 为 Number
    1. 先调用 obj 的 valueOf 方法,如果为原始值,则 return ,否则进行第 2 步
    2. 调用 obj 的 toString 方法,如果为原始值, 则 return ,否则第 3 步
    3. 抛出 TypeError 异常
  • Type 为 空
    1. 如果该对象为 Date,则 type 被设置为 String
    2. 否则,type 被设置为 Number

关于 Date 类型的特殊说明:对于 Date 的数据类型,我们更多时候是希望得到时间后面的字符串,而非时间戳,如果是number的话,则取到的是对应的时间戳(毫秒值),但显然字符串是使用得更多的。

所以综上所述,ToPrimitive转换成哪种原始类型主要取决于type,如果指定则按照指定类型转换,如果不指定的话分为两种情况:Date类型的为String,其余对象为number。那么问题来了,什么时候会指定type的类型呢?那就要看上面提到的两种转换方式了:toString和valueOf,我们要知道的是,toString()和valueOf()在特定的场合下会自行调用。

  1. toString()

    该方法返回一个表示该对象的字符串,每个对象都有一个toString()方法,当对象被表示为文本值或者当以期望字符串的方式引用对象时,该方法被自动调用。

  2. 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