0%

隐式类型转换

在javascript中隐式类型转换总是返回基本类型值,如字符串、数字、布尔值,不会返回对象或者函数。所以我们在介绍隐式类型转换之前首先来看一看字符串、数字、布尔值之间类型转换的基本规则。这里涉及到ToStringToNumberToBoolean,同时我们还会介绍ToPrimitive

一、抽象值操作

(一)ToString

ToString负责处理非字符串到字符串的强制类型转换。

(1)基本类型的值转化为字符串的基本规则:

1. null转化为"null"
2. undefined转化为"undefined" 
3. true转化为"true"
4. 数字的字符串转化规则遵循通用规则,不过那些极小或者极大的数值使用指数形式:

var a = 1.07 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000
a.toString()  // "1.07e21"

(2)对于普通对象来说,如果没有自定义toString()方法,返回"[object Object]"。如果有自己的toString()方法就会调用该方法并返回值。

(3)数组的toString()返回所有单元字符串化以后再用”,”连接起来:
var a = [1,2,3]
a.toString() // “1,2,3”

(4)日期、正则、函数也遵循通用规则。

(二)ToNumber

(1)基本类型的值转化为数字的基本规则:

1. null转化为0
2. undefined转化为NaN
3. true转化为1,false转化为0
4. 字符串的处理遵循通用规则

Number("23")  // 23
Number("")    // 0

(2)对象或者数组首先会被转化为相应的基本类型,如果返回的是非数字的基本类型,再按照以上规则进行转化。其中对象转化为基本类型的时候会使用ToPrimitive操作。

(三)ToPrimitive

ToPrimitive操作会首先检查对象是否有valueOf()方法,如果有并且返回基本类型的值,就调用该方法进行类型转化。如果没有就使用toString()返回的值。

如果valueOf()toString()均不返回基本类型的值,就会产生TypeError错误。

如果不对对象和数组的valueOf()toString()方法进行重写,那么:

(1)对象的valueOf()返回对象本身,toString()返回"[object Object]"

(2)数组的valueOf()返回数组本身,toString()返回所有单元字符串化以后再用”,”连接起来。

1
2
3
4
5
6
7
8
9
var a = {
name: 'sillywa'
}
var b = [1,2,3]
a.valueOf() // { name: 'sillywa' }
a.toString() // "[object Object]"

b.valueOf() // [1,2,3]
b.toString() // "1,2,3"

(四)ToBoolean

  1. null转化为false
1
Boolean(null)  // false
  1. undefined转化为false
    1
    Boolean(undefined)  // false
  2. 除””以外,所有字符串转化为true
    1
    2
    3
    Boolean("")  // fasle
    Boolean("abc") // true
    Boolean('0') // true
  3. 除0(包括+0和-0)和NaN外,所有数字转化为true
    1
    2
    3
    Boolean(0)  // false
    Boolean(NaN) // false
    Boolean(-9) // true
  4. 所有对象转化为true
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Boolean({})  // true
    Boolean([]) // true

    // 需要注意的是通过new关键字得到的是一个对象
    var a = new Boolean(false)
    var b = new Number(0)
    var c = new String('')
    var d = Boolean(a && b && c)
    d // true

    二、隐式类型转化

    (一)字符串和数字之间的隐式类型转化

    (1)数字转化为字符串

+运算符既能用于数字相加,也能用于字符串拼接。那么javascript是怎么判断我们要执行那个操作的呢?例如:

1
2
3
4
5
6
7
8
9
10
11
12
var a = '42'
var b = '0'

var c = 42
var d = 0

var e = 42
var f = '0'

a + b // "420"
c + d // 42
e + f // "420"

以上代码不难理解,通常我们认为+运算符两边只要有一个操作数是字符串就会执行字符串的拼接操作,但是实际情况更为复杂,例如:

1
2
3
var a = [1,2]
var b = [3,4]
a + b // "1,23,4"

a,b都不是字符串,但是它们都被转化为字符串进行拼接操作,原因何在?

简单的理解应当是如果+运算符其中一个是字符串或者可以通过ToPrimitive(针对于对象,包括数组)转化为字符串,则执行字符串的拼接;否则执行数字相加。

需要注意的是如果是 + '42'代表强制类型转化为数字,即 42

(2)字符串转化为数字

- , * , /都可以用来将字符串转化为数字,其规则与+类似

1
2
3
var a = '3.14'
var b = a - 0
b // 3.14

同样对于对象和数组也是一样

1
2
3
var a = [2]
var b = [1]
a - b // 1

为了执行减法运算,a、b都需要被转化为数字,首先通过ToPrimitive转化为字符串再转化为数字。

(二)布尔值到数字的隐式类型转化

简单举了例子:

1
2
1 + false  // 1
1+ true // 2

(三)隐式类型转化为布尔值

以下几种情况会发生隐式类型转化为布尔值

  1. if(..)条件判断语句
  2. for()中的条件判断
  3. while()do..while(..)中的条件判断
  4. ? : 三目运算符中的条件判断
  5. 逻辑运算符 || && 左边的操作数

(四)|| 和 &&

ES5规范中有如下描述

&&|| 运算符并不一定返回布尔值,而是两个操作数其中一个的值

例如:

1
2
3
4
5
6
7
8
9
var a = 42
var b = 'abc'
var c = null

a || b // 42
a && b // 'abc'

c || b // 'abc'
c && b // null

|| 和 && 首先会对第一个操作数进行条件判断,如果其不是布尔值,会被转化为布尔值,在进行判断。

对于 || 如果第一个操作数返回true则返回第一个操作数的值,如果第一个操作数返回false就返回第二个操作数的值。

对于 && 如果第一个操作数返回true则返回第二个操作数的值,如果第一个操作数返回false就返回第一个操作数的值。

本篇就介绍到这里,下篇介绍隐式类型转换之(宽松相等和严格相等)。