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]] 内部方法,采用以下步骤:

  1. str = O.toString();
  2. 如果str为原始值,返回str;
  3. val = O.valueOf();
  4. 如果val为原始值,返回val;
  5. 抛出一个 TypeError 异常。

当用 Number hint 调用 O 的 [[DefaultValue]] 内部方法,采用以下步骤:

  1. val = O.valueOf();
  2. 如果val为原始值,返回val;
  3. str = O.toString();
  4. 如果str为原始值,返回str;
  5. 抛出一个 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 运算流程如下:

  1. 令 lprim 为 ToPrimitive(lval).
  2. 令 rprim 为 ToPrimitive(rval).
  3. 如果 Type(lprim) 为 String 或者 Type(rprim) 为 String,则: 返回由 ToString(lprim) 和 ToString(rprim) 连接而成的字符串.
  4. 返回将加法运算作用于 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 的 - * / 运算符流程如下:

  1. 令 lnum 为 ToNumber(lval).
  2. 令 rnum 为 ToNumber(rval).
  3. 返回 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)

A === 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

参考

猜你喜欢

转载自www.cnblogs.com/whosMeya/p/12545927.html