對於普通對象來講,除非自行定義toString方法,不然就會調用Object.prototype.toString()方法,若是對象有本身的toString方法,字符串化就會調用該方法並使用其返回值。數組
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
JavaScript中的值能夠分爲能被強制轉換爲false的值和能被強制轉換爲true的值兩類。
假值:安全
真值:除了以上列表的均可以理解爲是真值,全部對象都是真值函數
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
字符串和數字之間的轉換是經過 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
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
即能用於數字加法,也能用於字符串拼接
若是 + 的其中一個操做數是字符串(或者經過對其調用 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"
根據 ToPrimitive抽象操做規則,a + ""會對a調用valueOf()方法,而後經過ToString抽象 操做將返回值轉換爲字符串。而 String(a) 則是直接調用 ToString()。它們最後返回的都是字符串,但若是 a 是對象而非數字結果可能會不同對象
let a = { valueOf: function() { return 42; }, toString: function() { return 4; } }; a + ""; // "42" String( a ); // "4"
-是數字減法運算符,所以a - 0會將a強制類型轉換爲數字。也可使用a * 1和a /1,由於這兩個運算符也只適用於數字,只不過這樣的用法不太常見ip
let a = [3]; let b = [1]; a - b; // 2
下面的狀況會發生 布爾值隱式強制類型轉換:
(1) if (..)語句中的條件判斷表達式。字符串
(2) for ( .. ; .. ; .. )語句中的條件判斷表達式(第二個)。
(3) while (..) 和 do..while(..) 循環中的條件判斷表達式。
(4) ? :中的條件判斷表達式。
(5) 邏輯運算符 ||(邏輯或)和 &&(邏輯與)左邊的操做數(做爲條件判斷表達式)。
以上狀況中,非布爾值會被隱式強制類型轉換爲布爾值,遵循前面介紹過的 ToBoolean 抽象操做規則。
== 容許在相等比較中進行強制類型轉換,而 === 不容許。== 和 === 都會檢查操做數的類型。區別在於操做數類型不一樣時它們的處理方式不一樣。
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 的結果。
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。
(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
(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,最後兩者相等
"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:
對於 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; }; }