js类型之隐式转化

字符串与数字之间的隐式转换

通过重载,+ 运算符即能用于数字加法,也能用于字符串拼接。

‘+’号和‘-’号

如果 + 的其中一个操作数是字符串(或者通过以上步骤可以得到字符串), 则执行字符串拼接;否则执行数字加法。
我们可以将数字和空字符串 “” 相 + 来将其转换为字符串:

var a = 42; 
var b = a + ""; 
b; // "42"
var a = "42"; 
var b = "0"; 
var c = 42; 
var d = 0; 
a + b; // "420"
c + d; // 42
var a = [1,2]; 
var b = [3,4]; 
a + b; // "1,23,4"

因为数组的 valueOf() 操作无法得到简单基本类型值,于是它转而调用 toString()。因此上例中的两 个数组变成了 “1,2” 和 “3,4”。+ 将它们拼接后返回 “1,23,4”。
a + “”(隐式)和前面的String(a)(显式)之间有一个细微的差别需要注意。
a + “” 会对 a 调用 valueOf() 方法,然后通过 ToString 抽象 操作将返回值转换为字符串。而 String(a) 则是直接调用 ToString()。

var a = {     
valueOf: function() { return 42; },    
toString: function() { return 4; }
  }; 
a + "";         // "42" 
String( a );    // "4"

隐式转换为布尔值

下面的情况会发生 布尔值隐式强制类型转换。

  1. if (…) 语句中的条件判断表达式。
  2. for ( … ; … ; … ) 语句中的条件判断表达式(第二个)。
  3. while (…) 和 do…while(…) 循环中的条件判断表达式。
  4. ? : 中的条件判断表达式。
  5. 逻辑运算符 ||(逻辑或)和 &&(逻辑与)左边的操作数(作为条件判断表达式)。

|| 和 &&

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

var a = 42; 
var b = "abc"; 
var c = null;  
a || b;     // 42 
a && b;     // "abc" 
c || b;     // "abc"
c && b;     // null

换一个角度来讲

a || b; // 大致相当于(roughly equivalent to): 
a ? a : b; 
a && b; // 大致相当于(roughly equivalent to): 
a ? b : a;

既然返回的不是 true 和 false,为什么 a && (b || c) 这样的表达式在 if 和 for 中没出过问题

var a = 42;
 var b = null;
  var c = "foo"; 
 
if (a && (b || c)) {   
  console.log( "yep" );
   }

这里 a && (b || c) 的结果实际上是 “foo” 而非 true,然后再由 if 将 foo 强制类型转换为 布尔值,所以最后结果为 true。

Symbol 符号的强制类型转换

var s1 = Symbol( "cool" ); String( s1 );     // "Symbol(cool)" 
 
var s2 = Symbol( "not cool" ); s2 + "";      // TypeError

抽象相等

非常规情况

  • NaN 不等于 NaN(参见第 2 章)
  • +0 等于 -0(参见第 2 章)

字符串与数字比较相等比较

var a = 42; 
var b = "42"; 
a === b;    // false 
a == b;     // true

具体怎么转换?是 a 从 42 转换为字符串,还是 b 从 “42” 转换为数字?
ES5 规范 11.9.3.4-5 这样定义:
(1) 如果 Type(x) 是数字,Type(y) 是字符串,则返回 xToNumber(y) 的结果。
(2) 如果 Type(x) 是字符串,Type(y) 是数字,则返回 ToNumber(x)y 的结果。

其他类型和布尔类型之间的相等比较

var a = "42"; 
var b = true; 
a == b; // false

规范 11.9.3.6-7 是这样说的:
(1) 如果 Type(x) 是布尔类型,则返回 ToNumber(x)y 的结果;
(2) 如果 Type(y) 是布尔类型,则返回 x
ToNumber(y) 的结果。

var x = true; 
var y = "42"; 
x == y; // false

Type(x) 是布尔值,所以 ToNumber(x) 将 true 强制类型转换为 1,变成 1==“42”,二者的 类型仍然不同,“42” 根据规则被强制类型转换为 42,最后变成 1==42,结果为 false。
反过来也一样:

var x = "42";
 var y = false; 
x == y; // false

Type(y) 是布尔值,所以 ToNumber(y) 将 false 强制类型转换为 0,然后 "42"==0再变成42==0,结果为 false。

也就是说,字符串 “42” 既不等于 true,也不等于 false。一个值怎么可以既非真值也非假 值,这也太奇怪了吧?
这个问题本身就是错误的,我们被自己的大脑欺骗了。
“42” 是一个真值没错,但 "42"中并没有发生布尔值的比较和强制类型转换。这里 不是 “42” 转换为布尔值(true),而是 true 转换为 1,“42” 转换为 42。这里并不涉及 ToBoolean,所以 “42” 是真值还是假值’=='本身没有关系!

null 和 undefined 之间的相等比较

null 和 undefined 之间的(==)也涉及隐式强制类型转换。
ES5 规范 11.9.3.2-3 规定:
(1) 如果 x 为 null,y 为 undefined,则结果为 true。
(2) 如果 x 为 undefined,y 为 null,则结果为 true
在双等号中 null 和 undefined 相等(它们也与其自身相等),除此之外其他值都不存在这种 情况。

对象和非对象之间的相等比较

关于对象(对象 / 函数 / 数组)和标量基本类型(字符串 / 数字 / 布尔值)之间的相等比 较,
ES5 规范 11.9.3.8-9 做如下规定:
(1) 如果 Type(x) 是字符串或数字,Type(y) 是对象,则返回 x== ToPrimitive(y) 的结果;
(2) 如果 Type(x) 是对象,Type(y) 是字符串或数字,则返回 ToPromitive(x)==y 的结果。

== 这里只提到了字符串和数字,没有布尔值,因为布尔值会先被强制类型转换为数字。==

比较少见的情况

假值相等的情况

下面分别列出了常规和非常规的情况:

"0"==null;           // false
"0" == undefined;      // false 
"0" == false;          // true -- 晕!
"0" == NaN;            // false 
"0" == 0;              // true
"0" == "";             // false 
false == null;         // false
false == undefined;    // false 
false == NaN;          // false 
false == 0;            // true -- 晕!
false == "";           // true -- 晕!
false == [];           // true -- 晕!
 false == {};           // false 
"" == null;            // false
"" == undefined;       // false 
"" == NaN;             // false 
"" == 0;               // true -- 晕!
"" == [];              // true -- 晕!
 "" == {};              // false 
0 == null;             // false 
0 == undefined;        // false
0 == NaN;              // false
0 == [];               // true -- 晕!
0 == {};               // false

极端情况

[] == ![]   // true

根据 ToBoolean 规则,它会进行布尔 值的显式强制类型转换(同时反转奇偶校验位)。所以 [] == ![]变成了[] == false。前 面我们讲过 false == [],最后的结果就顺理成章了。

2 == [2];       // true
 "" == [null];   // true

介绍 ToNumber 时我们讲过,数组的 valueOf() 返回数组本身, 所以强制类型转换过程中数组会进行字符串化
第一行中的 [2] 会转换为 “2”,然后通过 ToNumber 转换为 2。
第二行中的 [null] 会直接转 换为 “”。

0 == "\n"; // true
“”、"\n"(或者 " " 等其他空格组合)等空字符串被 ToNumber 强制类型转换 为 0

42 == "43";                        // false 
"foo" == 42;                       // false
"true" == true;                    // false 
42 == "42";                        // true
"foo" == [ "foo" ];                // true

总结:
图片来源地址:https://dorey.github.io/JavaScript-Equality-Table/(需要)
js类型之隐式转化_第1张图片
js类型之隐式转化_第2张图片
js类型之隐式转化_第3张图片

你可能感兴趣的:(你不知道的js)