正经文章的地方

相等判定中的隐式类型转换

一、非常规特殊情况

NaN !== NaN
+0 === -0

二、相等比较中的类型转换原则

字符串 —— 数字
Type(x) 左侧为数字,Type(y) 是字符串,x == y 则返回 x == ToNumber(y)
Type(y) 左侧为字符串,Type(x) 是数字,x == y 则返回 ToNumber(x) == y
小结:数字和字符串比较,则字符串变为数字。

其他类型 —— 布尔值
Type(x) 左侧为布尔类型,Type(y) 是其他类型,x == y 则返回 ToNumber(x) == y
Type(y) 右侧为布尔类型,Type(x) 是其他类型,x == y 则返回 x == ToNumber(y)
小结:布尔值和其他值比较,则布尔值变为数字。
注意:== 判定不等于 ToBoolean,所以==判定并不直接决定一个值为真值还是假值。

null —— undefined
在 == 比较中,null和undefined是一回事,可以互相转换。

对象 —— 非对象
Type(x) 左侧为基本类型,Type(y) 右侧为对象,x == y 则返回 x == ToPrimitive(y)
Type(x) 左侧为对象,Type(y) 右侧为基本类型,x == y 则返回 ToPrimitive(x) == y
小结:对象和基本类型比较,一律把对象ToPrimitive。

PS:相同类型比较时,对象和对象比较并不是判定值是否相等,而是判定是否为同一个引用,不需要类型转换。例如[] != [],{} != {}。

三、相等判定中的特殊情况

  1. 由于修改原生prototype中的valueOf导致的转换错误带来的特殊情况
  2. 七种false positive假真值,全部是由于类型转换时会转变成数字导致的
    1. “0” == false // 字符串和布尔值都会被转换类型变成数字,得到 0 == 0
    2. false == 0 // 同上
    3. false == “” // Number(“”) = 0
    4. false == [] // Number([]) = 0
    5. “” == 0
    6. “” == []
    7. 0 == []
  3. 极端情况
    1. [] == ![] // 左侧对象转换成数字0,右侧![]为布尔值false,同样转换成0
    2. 2 == [2] // ToPromitive([2]) = “2” 再作为String进行ToNumber得到2
    3. “” == [null] // ToPromitive([null]) = “”
    4. 0 == “\n” // “”、”\n”、” “等空字符串全部被ToNumber转换为0

四、ES5 – ToNumber 和 ToPrimitive 类型转换

  1. ToNumber —— 转换为数字
    1. undefined → NaN
    2. null → +0
    3. Boolean → true=1, false=0
    4. Number直接输出数字
    5. String → 同string转数字,从左到右解析,+-e0x等各自按照数字中的对应意义来解析(例:”0xA” → 10)
    6. Object → 先ToPrimitive再返回ToNumber
    7. 一切处理失败的情况 → NaN
    8. 对0开头的内容依然按照十进制处理
  2. ToPrimitive —— 转换为基本类型
    1. 未定义、空、布尔、数字、字符串,这些本来就是基本类型,直接返回不处理
    2. 对象:调用内部的defaultValue来检查是否含有valueOf方法
      1. 如果有valueOf且返回基本类型值,则直接返回
      2. 如果没有,用toString方法返回值来进行转换
      3. 如果两者都没有,返回TypeError
[CASE 1]:

var testValue = {
	valueOf: function() { return "0xA" },
	toString: function() { return "02" }
}

console.log(Number(testValue)) // 输出10,调用了valueOf且对"0xA"进行了toNumber变为十六进制的10
console.log(String(testValue)) // 输出"02",调用了toString直接输出
console.log(10 == testValue)   // 输出 true,类型转换后值相等
console.log(10 === testValue)  // 输出false,类型不同

// 如果toString返回的不是string,也不是简单值(数字、布尔、null),而是例如[2,4]等值,则调用valueOf返回,也就是返回"0xA"
[CASE 2]: 
// case 2 参考<a href="http://www.cnblogs.com/ziyunfei/archive/2012/09/18/2691062.html">Converting a value to string in JavaScript</a>

var obj = {
    valueOf: function () {
        console.log("valueOf");
        return {}; // 不是原始值,继续执行
    },
    toString: function () {
        console.log("toString");
        return {}; // 不是原始值,继续执行
    }
}; 

console.log("" + obj);
// "valueof"
// "toString"
// Uncaught TypeError: Cannot convert object to primitive value