深入理解JavaScript隐式类型转换(详解 + - * / ==)
JavaScript 在 运算 或 比较 之前, 会自动进行隐式类型转换. 下面我们来仔细讲一讲 + - * / == 运算符经历了哪些过程.
类型转换
ECMAScript 运行时系统会在需要时从事自动类型转换。为了阐明某些结构的语义,定义一集转换运算符是很有用的。这些运算符不是语言的一部分;在这里定义它们是为了协助语言语义的规范。
- ToPrimitive
- ToNumber
- ToString
- ToBoolean
- ToInteger
- ToInt32:(32 位有符号整数)
- ToUint32:(32 位无符号整数)
- ToUint16:(16 位无符号整数)
- ToObject
下面详细讲讲前三种
ToPrimitive
转为原始类型.
ToPrimitive(input, PreferredType)
| 输入类型 | 结果 | 
|---|---|
| Undefined | 结果等于输入的参数(不转换)。 | 
| Null | 结果等于输入的参数(不转换)。 | 
| Boolean | 结果等于输入的参数(不转换)。 | 
| Number | 结果等于输入的参数(不转换)。 | 
| String | 结果等于输入的参数(不转换)。 | 
| Object | 返回该对象的默认值。 对象的默认值由把 PreferredType 传入作为hint参数调用对象的内部方法[[DefaultValue]]得到 | 
对象内部方法 [[DefaultValue]] (hint)
当用 String hint 调用 O 的 [[DefaultValue]] 内部方法,采用以下步骤:
- str = O.toString();
- 如果str为原始值,返回str;
- val = O.valueOf();
- 如果val为原始值,返回val;
- 抛出一个 TypeError 异常。
当用 Number hint 调用 O 的 [[DefaultValue]] 内部方法,采用以下步骤:
- val = O.valueOf();
- 如果val为原始值,返回val;
- str = O.toString();
- 如果str为原始值,返回str;
- 抛出一个 TypeError 异常。
当不用 hint 调用 O 的 [[DefaultValue]] 内部方法时, 如果 O 为Date, 则hint=String, 除此之外, hit=Number。
例子:
ToPrimitive({})
解析:
    数据类型为 Object, 调用[[DefaultValue]]
    没有用 hint 调用, 则 hint 为 Number
    val = O.valueOf(); 
    val 是 {}, 不是原始值
    str = O.toString();
    str 是 '[object Object]', 是原始值, 返回'[object Object]'
结果: '[object Object]'
ToNumber
转为数字类型.(是 Number(value) 的实现)
| Input Type | Result | 
|---|---|
| Undefined | NaN | 
| Null | +0 | 
| Boolean | true: 1, false: +0 | 
| Number | 结果等于输入的参数(不转换)。 | 
| String | 将字符串转换为数字。 | 
| Object | Apply the following steps: 1. Call ToPrimitive(input argument, hint Number). 2. Call ToNumber(Result(1)). 3. Return Result(2). | 
ToString
转为字符串类型.(是 String(value) 的实现)
| 输入类型 | 结果 | 
|---|---|
| Undefined | "undefined" | 
| Null | "null" | 
| Boolean | 如果参数是 true,那么结果为 "true"。 如果参数是 false,那么结果为 "false"。 | 
| Number | 将数字转换为字符串。 | 
| String | 结果等于输入的参数(不转换)。 | 
| Object | Apply the following steps: 1. Call ToPrimitive(input argument, hint String). 2. Call ToString(Result(1)). 3. Return Result(2). | 
例子:
var obj = {
    valueOf: function () {
        return 1;
    },
    toString: function () {
        return 2;
    }
}
Number(obj) 
解析:
    obj 类型 Object, 调用 ToPrimitive(obj, Number)
    用 Number hint 调用 obj 的 [[DefaultValue]] 内部方法
    调用 obj 的 valueOf 方法, 结果为 1
    返回 ToNumber(1)
结果: 1
String(obj) 
解析:
    obj 类型 Object, 调用 ToPrimitive(obj, String)
    用 String hint 调用 obj 的 [[DefaultValue]] 内部方法
    调用 obj 的 toString 方法, 结果为 2
    返回 ToString(2)
结果: '2'
类型转换的实际运用
加号运算符:+
lval + rval 运算流程如下:
- 令 lprim 为 ToPrimitive(lval).
- 令 rprim 为 ToPrimitive(rval).
- 如果 Type(lprim) 为 String 或者 Type(rprim) 为 String,则: 返回由 ToString(lprim) 和 ToString(rprim) 连接而成的字符串.
- 返回将加法运算作用于 ToNumber(lprim) 和 ToNumber(rprim) 的结果.
例子:
([] + {})
解析:
    1. lprim = ToPrimitive([]); // ''
    2. rprim = ToPrimitive({}); // '[object Object]'
    3. lprim 和 rprim 都为字符串, 返回 ToString('') + ToString('[object Object]') // '[object Object]'
结果: '[object Object]'
(undefined + {})
解析:
    1. lprim = ToPrimitive([]); // undefined;
    2. rprim = ToPrimitive({}); // '[object Object]';
    3. Type(rprim) 为 String, 返回 ToString(undefined) + ToString('[object Object]') // 'undefined[object Object]'
结果: 'undefined[object Object]'
(undefined + 1)
解析:
    1. lprim = ToPrimitive([]); // undefined;
    2. rprim = ToPrimitive(1); // 1;
    3. Type(lprim) Type(rprim) 都不是 String;
    4. 返回 ToNumber(undefined) + ToNumber(1) // NaN
结果: NaN
其他运算符:- * /
lval 和 rval 的 - * / 运算符流程如下:
- 令 lnum 为 ToNumber(lval).
- 令 rnum 为 ToNumber(rval).
- 返回 ToNumber(lprim) 和 ToNumber(rprim) 运算的结果.
非严格相等:==
| 被比较值 B | |||||||
|---|---|---|---|---|---|---|---|
| Undefined | Null | Number | String | Boolean | Object | ||
| 被比较值 A | Undefined | true | true | false | false | false | IsFalsy(B) | 
| Null | true | true | false | false | false | IsFalsy(B) | |
| Number | false | false | A === B | A === ToNumber(B) | A=== ToNumber(B)  | A== ToPrimitive(B) | |
| String | false | false | ToNumber(A) === B | A === B | ToNumber(A) === ToNumber(B) | ToPrimitive(B) == A | |
| Boolean | false | false | ToNumber(A) === B | ToNumber(A) === ToNumber(B) | A === B | ToNumber(A) == ToPrimitive(B) | |
| Object | false | false | ToPrimitive(A) == B | ToPrimitive(A) == B | ToPrimitive(A) == ToNumber(B) | 
 | |
例子:
[] == {}
-> this == this
-> false
[] == 0
-> ToPrimitive([]) == 0
-> '' == 0
-> ToNumber('') == 0
-> 0 == 0
-> true
[0] == 0
-> ToPrimitive([0]) == 0
-> '0' == 0
-> ToNumber('0') == 0
-> 0 == 0
-> true
[11] == 11
-> true
['0'] == false
-> ToPrimitive(['0']) == ToNumber(false)
-> '0' == 0
-> 0 == 0
-> true
({} == '[object Object]')
-> ToPrimitive({}) == '[object Object]'
-> '[object Object]' == '[object Object]'
-> true
参考
 
                    
                     
                    
                 
                    
                
 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号