你不知道的類型轉換

前言

相信咱們在工做中常常會遇到類型轉換的需求。可是類型轉換也分爲隱式強制類型轉換」(implicit coercion)和「顯式強制類型轉換」(explicit coercion)。 例如:javascript

var a = 42;
var b = a + ""; // 隱式強制類型轉換 
var c = String( a ); // 顯式強制類型轉換
複製代碼

顯式強制類型轉換明確告訴咱們哪裏發生了類型轉換,有助於提升代碼可讀性和可維 護性。 隱式強制類型轉換則沒有那麼明顯,是其餘操做的反作用。尤爲是 == 時,有時候咱們就會迷糊,不知道過程當中發生了什麼,感受上好像是顯式強制類型轉 換的反面,實際上隱式強制類型轉換也有助於提升代碼的可讀性,今天咱們就來說一講兩種強制類型轉換.java

顯式強制類型轉換

顯式強制類型轉換是那些顯而易見的類型轉換,旨在讓代碼更加清晰易讀數組

字符串和數字之間的顯式轉換

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().ui

一元運算 + 被廣泛認爲是顯式強制類型轉換spa

顯式解析數字字符串

解析字符串中的數字和將字符串強制類型轉換爲數字的返回結果都是數字。但解析和轉換 二者之間仍是有明顯的差異.解析容許字符串中含有非數字字符,解析按從左到右的順序,若是遇到非數字字符就停 止。而轉換不容許出現非數字字符,不然會失敗並返回 NaNprototype

var a = "42";
    var b = "42px";
    Number( a );    // 42
    parseInt( a );  // 42
    Number( b );    // NaN
    parseInt( b );  // 42
複製代碼

顯式轉換爲布爾值

咱們可使用Boolean(..) 和!!,可是!!是咱們會經常使用的。code

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]],以數字做爲上下文。 若是 + 的其中一個操做數是字符串(或者經過以上步驟能夠獲得字符串), 則執行字符串拼接;不然執行數字加法ip

var a = 42;
     var b = a + "";
     b; // "42"
複製代碼

這裏有一個小差異須要注意:a + ""(隱式)和前面的String(a)(顯式)之間有一個細微的差異須要注意。根據 ToPrimitive抽象操做規則,a + ""會對a調用valueOf()方法,而後經過ToString抽象 操做將返回值轉換爲字符串。而 String(a) 則是直接調用 ToString()。 例如:ci

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);
}
複製代碼
  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》

相關文章
相關標籤/搜索