你不知道的型別轉換
相信我們在工作中經常會遇到型別轉換的需求。但是型別轉換也分為隱式強制型別轉換”(implicit coercion)和“顯式強制型別轉換”(explicit coercion)。 例如:
var a = 42; var b = a + ""; // 隱式強制型別轉換 var c = String( a ); // 顯式強制型別轉換 複製程式碼
顯式強制型別轉換明確告訴我們哪裡發生了型別轉換,有助於提高程式碼可讀性和可維 護性。 隱式強制型別轉換則沒有那麼明顯,是其他操作的副作用。尤其是 == 時,有時候我們就會迷糊,不知道過程中發生了什麼,感覺上好像是顯式強制型別轉 換的反面,實際上隱式強制型別轉換也有助於提高程式碼的可讀性,今天我們就來講一講兩種強制型別轉換.
顯式強制型別轉換
顯式強制型別轉換是那些顯而易見的型別轉換,旨在讓程式碼更加清晰易讀
字串和數字之間的顯式轉換
var a = 42; var b = String( a ); var e = a.toString(); var c = "3.14"; var d = Number( c ); var f = +c; b; // "42" e; // ''42 d; // 3.14 f; //3.14 複製程式碼
toString()其中涉及隱式轉換。因為 toString() 對 42 這樣的基本型別值不適用,所以 JavaScript 引擎會自動為 42 建立一個封 裝物件,然後對該物件呼叫 toString().
一元運算 + 被普遍認為是顯式強制型別轉換
顯式解析數字字串
解析字串中的數字和將字串強制型別轉換為數字的返回結果都是數字。但解析和轉換 兩者之間還是有明顯的差別.解析允許字串中含有非數字字元,解析按從左到右的順序,如果遇到非數字字元就停 止。而轉換不允許出現非數字字元,否則會失敗並返回 NaN
var a = "42"; var b = "42px"; Number( a );// 42 parseInt( a );// 42 Number( b );// NaN parseInt( b );// 42 複製程式碼
顯式轉換為布林值
我們可以使用Boolean(..) 和!!,但是!!是我們會常用的。
var a = "0"; var b = []; var c = {}; var d = ""; var e = 0; var f = null; var g; !!a; // true !!b; // true !!c; // true !!d; // false !!e; // false !!f; // false !!g; // false 複製程式碼
隱式強制型別轉換
隱式強制型別轉換指的是那些隱蔽的強制型別轉換,副作用也不是很明顯,會讓程式碼變得晦澀難懂
字串和數字之間的隱式強制型別轉換
根據規範,如果某個運算元是字串或者能夠通過以下步驟轉換為字串 的話,+ 將進行拼接操作。如果其中一個運算元是物件(包括陣列),則首先對其呼叫 ToPrimitive 抽象操作,該抽象操作再呼叫 [[DefaultValue]],以數字作為上下文。 如果 + 的其中一個運算元是字串(或者通過以上步驟可以得到字串), 則執行字串拼接;否則執行數字加法
var a = 42; var b = a + ""; b; // "42" 複製程式碼
這裡有一個小差別需要注意:a + ""(隱式)和前面的String(a)(顯式)之間有一個細微的差別需要注意。根據 ToPrimitive抽象操作規則,a + ""會對a呼叫valueOf()方法,然後通過ToString抽象 操作將返回值轉換為字串。而 String(a) 則是直接呼叫 ToString()。 例如:
var a = { valueOf: function() { return 42; }, toString: function() { return 4; } }; a + "";// "42" String( a );// "4" 複製程式碼
如果執行-操作,它們首先被轉換為字串(通過toString()),然後再轉換為數字。
var a = [3]; var b = [1]; a - b; // 2 複製程式碼
布林值到數字的隱式強制型別轉換
以下情況中,非布林值會被隱式強制型別轉換為布林值,遵循前面介紹過的 ToBoolean 抽 象操作規則 (1)if (..)語句中的條件判斷表示式。 (2)for ( .. ; .. ; .. )語句中的條件判斷表示式(第二個)。 (3) while (..) 和 do..while(..) 迴圈中的條件判斷表示式。 (4)? :中的條件判斷表示式。 (5) 邏輯運算子 ||(邏輯或)和 &&(邏輯與)左邊的運算元(作為條件判斷表示式)。
var a = 42; var b = "abc"; var c; var d = null; if (a) { console.log( "yep" ); // yep } while (c) { console.log( "nope, never runs" ); } c = d ? a : b; c;// "abc" if ((a && d) || c) { console.log( "yep" );// yep } 複製程式碼
符號的強制型別轉換
寬鬆相等(loose equals)== 和嚴格相等(strict equals)=== 都用來判斷兩個值是否“相 等”,但是它們之間有一個很重要的區別,特別是在判斷條件上,即== 允許在相等比較中進行強制型別轉換,而 === 不允許。
字串和數字之間的相等比較
字串和數字相互比較時,首先將字元中轉換為數字再來比較。 (1) 如果 Type(x) 是數字,Type(y) 是字串,則返回 x == ToNumber(y) 的結果。 (2) 如果 Type(x) 是字串,Type(y) 是數字,則返回 ToNumber(x) == y 的結果
var a = 42; var b = "42"; a == b // true 複製程式碼
其他型別和布林型別之間的相等比較
字串或數字等其他型別與布林型別比較時,先將布林型別轉換為數字再來和字串比較,接下來就是進行的字串和數字之間的相等比較,再進行一輪轉換來比較。 (1) 如果 Type(x) 是布林型別,則返回 ToNumber(x) == y 的結果; (2) 如果 Type(y) 是布林型別,則返回 x == ToNumber(y) 的結果
var x = true; var y = "42"; x == y; // false 複製程式碼
null 和 undefined 之間的相等比較
(1) 如果 x 為 null,y 為 undefined,則結果為 true。 (2) 如果 x 為 undefined,y 為 null,則結果為 true 在 == 中 null 和 undefined 相等(它們也與其自身相等),除此之外其他值都不存在這種 情況
var a = null; var b; a == b;// true a == null;// true b == null;// true a == false; // false b == false; // false a == "";// false b == "";// false a == 0;// false b == 0;// false 複製程式碼
物件和非物件之間的相等比較
物件和非物件之間的比較,首先對物件進行ToPromitive轉換,再進行比較。 (1) 如果 Type(x) 是字串或數字,Type(y) 是物件,則返回 x == ToPrimitive(y) 的結果; (2) 如果 Type(x) 是物件,Type(y) 是字串或數字,則返回 ToPromitive(x) == y 的結果
var a = 42; var b = [ 42 ]; a == b; // true 複製程式碼
比較少見的情況
1.隱式轉換返回其他數字
Number.prototype.valueOf = function() { return 3; }; new Number( 2 ) == 3;// true 複製程式碼
Number(2) 涉及 ToPrimitive 強制型別 轉換,因此會呼叫 valueOf()返回3. 思考題:下面程式碼中 a 在什麼情況下會列印 1?
var a = ?; if(a == 1 && a == 2 && a == 3){ conso.log(1); } 複製程式碼
- 完整性檢查
"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 -- 反人類 複製程式碼
我們來看看[] == ![]的轉換過程
[] == ![] // => [] == false // => [] == 0 // => 0 == 0 // true 複製程式碼
按照上述規範推敲兩邊的值,基本就不會出錯。並且這兩個原則可以讓我們有效地避免出錯 • 如果兩邊的值中有 true 或者 false,千萬不要使用 ==。 • 如果兩邊的值中有 []、"" 或者 0,儘量不要使用 ==。
參考連結:《你不知道的javascript》