JavaScript基礎---強制類型轉換

1、類型轉換規則

1.ToString

對於普通對象來講,除非自行定義toString方法,不然就會調用Object.prototype.toString()方法,若是對象有本身的toString方法,字符串化就會調用該方法並使用其返回值。數組

2.ToNumber

  • 對於基本類型其中true轉換爲1,false轉換爲0;undefined 轉換爲 NaN,null 轉換爲 0
  • 對於對象類型會首先轉換成爲基本類型值若是返回的是非數字的基本類型值,則再遵循基本類型轉換規則將其強制轉換爲數字。爲了將值轉換爲相應的基本類型值,抽象操做ToPrimitive會首先檢查該值是否有 valueOf() 方法。若是有而且返回基本類型值,再使用該值進行強制類型轉換。若是沒有就使用 toString() 的返回值(若是存在)來進行強制類型轉換。若是 valueOf() 和 toString() 均不返回基本類型值,會產生 TypeError 錯誤。
let a = {
    valueOf:function(){
        return "42";
    }
};
let b = {
    toString:function(){
        return "42";
    }
};
let c = [4,2];
c.toString = function(){
    return this.join(""); //"42"
};

Number(a);     //42
Number(b);     //42
Number(c);     //42
Number('');    //0
Number([]);    //0
Number(["abc"];//NaN

3.ToBoolean

JavaScript中的值能夠分爲能被強制轉換爲false的值和能被強制轉換爲true的值兩類。
假值:安全

  • undefined
  • null
  • false
  • +0、-0、NaN
  • ""

真值:除了以上列表的均可以理解爲是真值,全部對象都是真值函數

let a1 = new Boolean( false );
let b1 = new Number( 0 );
let c1 = new String( "" );
let d1 = Boolean(a1 && b1 && c1); //true

let a2 = [];
let b2 = {};
let c2 = function(){};
let d2 = Boolean(a2 && b2 && c2); //true

2、顯示強制類型轉換

1.字符串與數字之間的顯示轉換

字符串和數字之間的轉換是經過 String(..)Number(..) 這兩個內建函數。
除了 String(..) 和 Number(..) 之外,還有其餘方法能夠實現字符串和數字之間的顯式 轉換:this

let a = 42;
let b = a.toString();
let c = "3.14";
let d = +c;
b; // "42"
d; // 3.14

a.toString() 是顯式的,不過其中涉及隱式轉換。由於 toString() 對 42 這樣的基本類型值不適用,因此 JavaScript 引擎會自動爲 42 建立一個封裝對象,而後對該對象調用 toString()。這裏顯式轉換中含有隱式轉換。prototype

2.顯示轉換爲布爾值

let a = "0";
let b = [];
let c = {};
let d = "";
let e = 0;
let f = null;
let g;
Boolean( a ); // true
Boolean( b ); // true
Boolean( c ); // true
Boolean( d ); // false
Boolean( e ); // false
Boolean( f ); // false
Boolean( g ); // false

雖然 Boolean(..) 是顯式的,但並不經常使用。顯式強制類型轉換爲布爾值最經常使用的方法是 !!設計

let a = "0";
let b = [];
let c = {};
let d = "";
let e = 0;
let f = null;
let g;
!!a; // true
!!b; // true
!!c; // true
!!d; // false
!!e; // false
!!f; // false
!!g; // false

3、隱式強制類型轉換

1.字符串和數字之間的隱式強制類型轉換

(1)+運算符

即能用於數字加法,也能用於字符串拼接
若是 + 的其中一個操做數是字符串(或者經過對其調用 ToPrimitive 抽象操做獲得字符串), 則執行字符串拼接;不然執行數字加法。由於數組的 valueOf() 操做沒法獲得簡單基本類型值,因而它轉而調用 toString()。所以下例中的兩個數組變成了 "1,2" 和 "3,4"。+ 將它們拼接後返回 "1,23,4"。code

let a = "42";
let b = "0";
a + b; // "420"

let c = 42;
let d = 0;
c + d; // 42

let x = [1,2];
let y = [3,4];
x + y; // "1,23,4"

可使用+運算符進行字符串轉換,將數字和空字符串 "" 相 + 來將其轉換爲字符串

let a = 42;
let b = a + "";
b; // "42"

a + ""(隱式)和前面的String(a)(顯式)之間有一個細微的差異須要注意。

根據 ToPrimitive抽象操做規則,a + ""會對a調用valueOf()方法,而後經過ToString抽象 操做將返回值轉換爲字符串。而 String(a) 則是直接調用 ToString()。它們最後返回的都是字符串,但若是 a 是對象而非數字結果可能會不同對象

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

(2)從字符串強制類型轉換爲數字的狀況

-是數字減法運算符,所以a - 0會將a強制類型轉換爲數字。也可使用a * 1和a /1,由於這兩個運算符也只適用於數字,只不過這樣的用法不太常見ip

let a = [3];
let b = [1];
a - b; // 2

2.隱式強制類型轉換爲布爾值

下面的狀況會發生 布爾值隱式強制類型轉換:
(1) if (..)語句中的條件判斷表達式。字符串

(2) for ( .. ; .. ; .. )語句中的條件判斷表達式(第二個)。

(3) while (..) 和 do..while(..) 循環中的條件判斷表達式。

(4) ? :中的條件判斷表達式。

(5) 邏輯運算符 ||(邏輯或)和 &&(邏輯與)左邊的操做數(做爲條件判斷表達式)。

以上狀況中,非布爾值會被隱式強制類型轉換爲布爾值,遵循前面介紹過的 ToBoolean 抽象操做規則。

4、寬鬆相等和嚴格相等

== 容許在相等比較中進行強制類型轉換,而 === 不容許。== 和 === 都會檢查操做數的類型。區別在於操做數類型不一樣時它們的處理方式不一樣。

1.字符串和數字之間的相等比較

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

由於===沒有強制類型轉換,因此 a === b 爲 false,42 和 "42" 不相等。而 a == b 是寬鬆相等,即若是兩個值的類型不一樣,則對其中之一或二者都進行強制類型轉換。
轉換規則以下:
(1) 若是 Type(x) 是數字,Type(y) 是字符串,則返回 x == ToNumber(y) 的結果。
(2) 若是 Type(x) 是字符串,Type(y) 是數字,則返回 ToNumber(x) == y 的結果。

2.其餘類型和布爾類型之間的相等比較

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

轉換規則以下:
(1) 若是 Type(x) 是布爾類型,則返回 ToNumber(x) == y 的結果;
(2) 若是 Type(y) 是布爾類型,則返回 x == ToNumber(y) 的結果。

上例中Type(x)是布爾值,因此ToNumber(x)將true強制類型轉換爲1,變成1 == "42",兩者的類型仍然不一樣,"42" 根據規則被強制類型轉換爲 42,最後變成 1 == 42,結果爲 false。

3.null和undefined之間的相等比較

(1) 若是 x 爲 null,y 爲 undefined,則結果爲 true。
(2) 若是 x 爲 null,y 不是 undefined或者null,則結果爲 false。
(3) 若是 x 爲 undefined,y 爲 null,則結果爲 true。
(4)若是 x 爲 undefined,y 不是 undefined或者null,則結果爲 false。

let a = null;
let 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

4.對象和非對象之間的相等比較

(1) 若是 Type(x) 是字符串或數字,Type(y) 是對象,則返回 x == ToPrimitive(y) 的結果;
(2) 若是 Type(x) 是對象,Type(y) 是字符串或數字,則返回 ToPromitive(x) == y 的結果。

let a = 42;
var b = [ 42 ];
a == b; // true

[ 42 ] 首先調用 ToPromitive 抽象操做,返回 "42",變成 "42" == 42,而後 又變成 42 == 42,最後兩者相等

5.比較少見的狀況

(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

(2)安全運用隱式強制類型轉換

  • 若是兩邊的值中有 true 或者 false,千萬不要使用 ==
  • 若是兩邊的值中有 []、"" 或者 0,儘可能不要使用 ==。

這時最好用 === 來避免不經意的強制類型轉換。這兩個原則可讓咱們避開幾乎全部強制 類型轉換的坑。

5、Object.is(..) 判斷兩個值是否相等

如下狀況返回true:

  • 兩個值都是 undefined
  • 兩個值都是 null
  • 兩個值都是 true 或者都是 false
  • 兩個值是由相同個數的字符按照相同的順序組成的字符串
  • 兩個值指向同一個對象
  • 兩個值都是數字而且
  • 都是正零 +0
  • 都是負零 -0
  • 都是 NaN
  • 都是除零和 NaN 外的其它同一個數字

對於 ES6 以前的版本,Object.is(..) 有一個簡單的 polyfill:

if (!Object.is) {
    Object.is = function(v1, v2) {
        // 判斷是不是-0
        if (v1 === 0 && v2 === 0) {
            return 1 / v1 === 1 / v2;
        }
        // 判斷是不是NaN 
        if (v1 !== v1) {
            return v2 !== v2;
        }
        // 其餘狀況
        return v1 === v2;
    };
}

參考文章:
JavaScript高級程序設計
你不知道的JavaScript(中卷)

相關文章
相關標籤/搜索