記不清在某處看見了這一比較,當時對強制轉換這塊理解的尚未特別清晰,故有此一文。覺得我會以標題的表達式來展開?那你就錯了,下面直接上[] == ![]是如何轉換的:javascript
本文旨在總結js中強制轉換的規則及觸發強制轉換的幾種場景。ES6標準中定義了六種原始類型,分別是Undefined,Null,String,Number,Boolean,Symbol。本文中的強制轉換指的是在代碼運行時,觸發了數值的隱式轉換,而不是代碼顯示的指定轉換操做。java
發生在原始類型之間的轉換,以我的的理解是其餘類型轉換爲String,Number或者Boolean類型。算法
其餘原始類型轉換爲String類型一般發生在+兩邊存在字符串時,會將+另外一邊的值轉換爲String類型。 考慮以下代碼:函數
var strAddNum = "test" + 1;
var numAddStr = 1 + "test";
var boolAddStr = true + "test";
var undAddStr = undefined + "";
var nullAddStr = null + "";
console.log(strAddNum);
console.log(numAddStr);
console.log(boolAddStr);
console.log(undAddStr);
console.log(nullAddStr);
複製代碼
代碼傳送門,以上代碼的運行結果均爲字符串。其餘原始類型轉換爲String類型基本是其值的字符串形式,具體以下:ui
Number轉爲字符串具體可參考ES2018 7.1.12.1章節編碼
注意:Symbol類型沒法轉換爲String類型。spa
轉換爲Number類型的狀況,+-*/%等運算中,除了+以外其餘運算均會轉換成Number類型,+運算時須要知足兩側未出現String類型,該值纔會被轉換爲Number類型。+運算時狀況較爲複雜,後面會專門描述其相關轉換規則。考慮以下代碼:code
var trueAddTrue = true + true;
var trueAddFalse = true + false;
var trueAdda0 = true + 0;
var nullAddTrue = null + true;
var undefinedAdd0 = undefined + 0;
var strAdd0 = "" + 0;
console.log(trueAddTrue);
console.log(trueAddFalse);
console.log(trueAdda0);
console.log(nullAddTrue);
console.log(undefinedAdd0);
console.log(strAdd0);
複製代碼
代碼傳送門,在運行代碼以前能夠先考慮下以上代碼答打印的結果分別是什麼?而後再運行,看是否符合你的預期。其餘原始類型轉換爲Number類型的具體以下:對象
注意:Symbol類型一樣沒法轉換爲Number類型。ip
轉換爲Boolean類型的狀況較爲簡單,除了如下狀況轉換爲Boolean類型會是false,其餘狀況均是true
ES中將對象轉換爲原始類型的算法,大體可描述爲三種情形:
上述三種情形中第一種情形優先級最高,第二三種情形優先級並列,具體須要根據使用場景判斷是哪種。其中的指定轉換提示是ES標準內部調用該算法時指定的。
第一種情形只有Symbol對象和Date對象內置了[Symbol.toPrimitive],且該屬性的writeable爲false,enumerable爲false,configurable爲true 對象轉換爲原始類型時發生的強制轉換非特殊狀況均爲第二種,第三種狀況較爲少見。在正常編碼工做中應該使用第二種情形就夠用了,第三種情形幾乎不會出現,要了解更多細節可查閱ES標準。
var test = {
[Symbol.toPrimitive]: function(hint) {
console.log(hint)
},
valueOf: function() {
console.log("valueOf")
},
toString: function() {
console.log("toString")
}
}
test + ""; //"default"
test * 0; //"number"
String(test); //"string"
複製代碼
代碼傳送門上述代碼指定了分別指定了test對象的[Symbol.toPrimitive],valueOf和toString函數,能夠觀察到並valueoOf和toString函數均未被調用,指定的[Symbol.toPrimitive]函數能夠接受一個提示參數,這個參數就是強制轉換時的強制轉換提示。這樣咱們在函數中就能夠根據轉換場景的不一樣分別返回不一樣的值。
在開始描述這個問題以前,能夠先思考一下,都有哪些場景會是強制的將原始類型轉換爲對象,其實這種場景幾乎在js代碼中隨處可見,考慮以下代碼:
var str = "testString";
str.replace("test", "");
複製代碼
如上代碼中定義的str的值並非一個對象而是一個原始類型String,原始類型顯然是沒有方法能夠調用的。
實際上這裏的str在執行str.replace時str其值會被強制轉換爲對象,獲得一個String類型的實例對象,而該實例的原型上定義了一系列方法,且該實例是沒法被獲取的,在執行完這行代碼後,該實例就會被回收,因此這裏的str依然是一個字符串。
考慮以下代碼:
var a = 3;
a.fn = function(){};
a.fn();
複製代碼
在js代碼中會出現強制轉換的場景一般有三種:
作一元+運算時,均會被強制轉爲Number類型,例如
var a = {
[Symbol.toPrimitive]: function(hint) {
console.log(hint); // number
if(hint === "number") {
return 2;
} else {
return 9;
}
}
};
console.log(+a); // 2
var b = "3";
console.log(+b); // 3
複製代碼
二元+運算爲幾種強制轉換中複雜度僅次於==比較的一種情形,我的總結其轉換步驟以下:
var a = "";
var b = {
[Symbol.toPrimitive]: function(hint) {
console.log(hint); // "default"
if(hint === "default") {
return 2;
} else {
return 9;
}
}
};
var c = a + b; //這裏b轉換爲原始類型返回的是Number類型2,因爲a是"",因此b被轉換爲"2",後與""拼接返回"2"
console.log(c); // "2"
var d = 3;
var e = {
[Symbol.toPrimitive]: function(hint) {
console.log(hint); // "default"
if(hint === "default") {
return 2;
} else {
return 9;
}
}
};
var f = d + e; //這裏e轉換爲原始類型返回的是Number類型2,因爲兩側均沒有String類型,則至第3步,強制轉換爲Number後返回兩側相加的結果5
console.log(f); // 5
複製代碼
這幾個運算符這涉及的強制轉換都是轉換爲Number類型的,因此這裏只要搞清楚轉換爲Number是怎樣的過程就能夠了。上文中已經對原始類型轉換爲Number類型作了描述,這裏補充一下Object轉換爲Number的過程:
var a = 8;
var b = {
[Symbol.toPrimitive]: function(hint) {
console.log(hint); // "number"
if(hint === "number") {
return 2;
} else {
return 9;
}
}
};
console.log(a-b); // 6
console.log(a/b); // 4
console.log(a*b); // 16
console.log(a%b); // 0
console.log(undefined * 0); //NaN
console.log(null * -1); // 0
console.log(false * -1); //0
console.log(true * -1); // -1
console.log("1" * -1); // -1
複製代碼
x === y,其具體比較步驟以下:
==比較的轉換規則雖然稍微多一點,實際上也就幾條規則,兩側的數值類型符合哪一種就按哪一種去轉換,只不過有的可能須要轉兩次,具體以下:
下面列舉一些可能有點違反直覺的比較
"0" == false; // true
false == 0; // true
false == ""; // true
false == []; // true
"" == 0; // true
"" == []; // true
0 == []; // true
[] == ![]; //true
複製代碼
這種情形到沒有太多可說的,基本上就是,除了undefined,null,+0,-0,NaN,""這六個值會被轉爲false,其餘狀況均爲true;
出現將不是Boolean類型的值強制轉換的狀況爲
其實上面描述了這麼多,平常開發環境中用到比較多的應該是做爲判斷條件,+,==這三種狀況了,這三種中最多見的應該是判斷條件的狀況了,這種狀況反而是最簡單的一種了。