JavaScript類型轉換機制及各類型檢查方法
在JavaScript中,我們通常會碰到有關於值比較的問題。由於JavaScript類型轉換機制的存在,往往會遇到一些尷尬的問題。比如我們會遇到這樣的問題 alert(true == 1); // 結果返回true 以及 alert([] == 0); // 結果依舊返回true 等等問題。在介紹JavaScript類型轉換機制之前,首先我們必須瞭解一下JavaScript的原始值及引用對象。
1 JavaScript的原始值及引用對象
JavaScript的值分爲兩種類型:原始類型和引用類型(也稱做對象)。
原始類型包括:字符串、數字、布爾值、null和undefined
引用類型包括:數組和函數
1.1 原始類型與引用類型的區別
1、原始類型的值是不可變的,引用類型的值是可變的。
var str1 = "hello"; // 首先存在一個爲"hello"的字符串,我們使用變量str1接收
var str2 = str1; // 然後我們將str1賦值給str2
str1 = str1.toUpperCase(); // 接着我們調用一下字符串的方法,將字符串中的字母全部大寫
alert(str2); // 最後我們輸出一下str2 結果依舊是 hello
當然舉這樣一個例子,事實上是說明,字符串中所有的方法看上去返回一個修改後的字符串,實際上返回的是一個新的字符串。對於數字和布爾值就更加明顯了--改變數字的值本身就說不通。
2、原始類型的比較,只有它們的值相等的時候它們才相等。對於字符串來說就不太好理解。
JavaScript規定字符串,當前僅當它們的長度相等及每個索引的字符都相等時,JavaScript才認爲他們相等。而引用類型的比較:當且僅當它們引用同一個對象時,它們才相等。那麼,即使兩個對象包含同樣的屬性及相同的值,它們也不一定是相等的。
var a = {x:1};
var b = {x:1};
alert("比較1:" + (a === b)); // 結果返回false
var a = [];
var b = [];
alert("比較2:" + (a === b)); // 結果返回false
var a = [];
var b = a;
var c = b;
alert("比較3:" + (a === b)); // 結果返回true
2 JavaScript類型轉換機制
瞭解了JavaScript的值的類型之後,我們再來看JavaScript類型轉換機制。JavaScript會根據需要自行轉換類型。這一點我們從以下示例就可以看出。
var str = "30";
str = str * 10; // 因爲執行乘法運算,乘法的兩邊都應該是數字類型,JavaScript會根據需要將str轉換爲數字類型
alert(str); // 結果返回300
var str2 = 30;
str2 = str2 + "10"; // 因爲執行+運算,因爲+的一遍包含字符串"10",因此我們可以將+看出連接符,JavaScript會根據需要將str轉換爲字符串
alert(str2); // 結果返回3010
2.1 JavaScript各類型之間的轉換對應表
根據《JavaScript權威指南》,以下表格說明了各類型之間的轉換。空單元格表示不必要也沒有執行轉換。
值 | 轉換爲 | |||
字符串 | 數字 | 布爾值 | 對象 | |
undefined | "undefined" | NaN | false | throws TypeError |
null | "null" | 0 | false | throws TypeError |
true | "true" | 1 | new Boolean(true) | |
false | "false" | 0 | new Boolean(false) | |
""(空字符串) | 0 | false | new String("") | |
"1.2"(非空,數字) | 1.2 | true | new String("1.2") | |
"one"(非空,非數字) | NaN | true | new String("one") | |
0 | "0" | false | new Number(0) | |
-0 | "0" | false | new Number(-0) | |
NaN | "NaN" | false | new Number(NaN) | |
Infinity | "Infinity" | true | new Number(Infinity) | |
-Infinity | "-Infinity" | true | new Number(-Infinity) | |
1(無窮大,非0) | "1" | true | new Number(1) | |
{}(任意對象) | 具體見下文 | 具體見下文 | true | |
[](任意數組) | "" | 0 | true | |
[9](一個數字元素的數組) | "9" | 9 | true | |
['a'](其他數組) | 使用join()方法 | NaN | true | |
function(){}(任意函數) | 具體見下文 | NaN | true |
說明:
(1)原始值到對象的轉換非常簡單。原始值通調用String(),Number(),或Boolean()構造函數,轉換成爲它們各自的包裝對象。
(2)null和undefined屬於例外,當它們用在期望是一個對象的地方時,都會造成一個類型錯誤(TypeError)異常,而不會執行正常的轉換
(3)對象到原始值的轉換比較複雜。具體請看後續分析。
2.2 顯示類型轉換
通過調用Boolean()、Number()、String()或Object()函數顯示的將數據轉換爲期望的類型的方法。
Number("1") ==> 1
String("true") ==> "true"
Boolean([]) ==> true
Object("3") ==> new Number("3")
需要注意的是:如果試圖將null或undefined轉換成爲對象,則會報類型錯誤(TypeError)具體如上表所示。 如果是Object()函數,則會返回一個新創建的空對象
2.3 隱式類型轉換
JavaScript中的某些運算符會做隱式轉換, 例如var x = "30"; +x; ==> 等價於 x-0。像這種通過JavaScript中的某些運算符達到數據類型轉換目的的方法稱之爲隱式轉換。
x + ""; // 等價於String(x);
+x; // 等價於Number(x);或 x - 0;
!!x; // 等價於Boolean(x);需要注意的是雙感嘆號
2.4 對象轉換爲字符串
1、 如果對象具有toString()方法,則調用這個方法,如果它的返回值是一個原始值,JavaScript將這個值轉換爲字符串(如果其本身不是字符串),並返回這個字符串結果。詳細的轉換對比上表。
(1)數組轉換爲字符串
數組轉換爲字符串時,調用toString()方法,該方法將數組轉換成一個字符串,並在元素間添加逗號後結合成結果字符串,例如:["1","2","3"].toString(); // ==> 1,2,3
var a = ["1","2","3"];
var b = "1,2,3";
alert(a == b);
(2)函數類轉化爲字符串
函數類轉換爲字符串時,通常toString()方法實際返回的是這個函數的實現定義表現方式。Eg:(function(x){f(x);}).toString; ==> // function(x){f(x);}
var a = "function(x){f(x);}";
var b = function(x){f(x);};
var c = function(x){
f(x);
};
console.log("a == b:" + (a == b));
console.log("a == c:" + (a == c));
console.log(c.toString());
2 、 如果對象沒有toString()方法,或者這個方法不返回一個原始值,那麼JavaScript會調用valueOf()方法。如果這個方法存在JavaScript則會調用它。如果返回值是原始值,JavaScript會將這個值轉換爲字符串(如果其本身不是字符串的話),並返回這個字符串結果。
var obj = {
name:"",
age:12,
valueOf:function(){
return "this is valueOf()"
}
};
alert("查看調用的方法:" + obj);
備註:根據《JavaScript權威指南》說明,理論上應該先調用toString(),如果沒有則調用valueOf()方法,而事實上則先調用valueOf()方法,然這一點我很費解。知道原因的朋友,麻煩留言一下。具體如下:
var obj = {
name:"",
age:12,
toString:function(){
return "this is toString()"
},
valueOf:function(){
return "this is valueOf()"
}
};
alert("查看調用的方法:" + obj);
3、否則, 無法從toString()或valueOf()獲得一個原始值。因此這時將拋出一個類型錯誤異常。
var obj = {
name:"",
age:12,
toString:function(){
return new Object();
},
valueOf:function(){
return new Object();
}
};
alert("查看調用的方法:" + obj);
2.5 對象轉換爲數字
對象轉換爲數字的過程與到字符串類似,只是它會首先嚐試使用valueOf()方法。
1、如果對象具有valueOf()方法,則調用這個方法,如果它的返回值是一個原始值,JavaScript將這個值轉換爲數字(如果其本身不是數字),並返回這個數字。詳細的轉換對比上表。
2 、 如果對象沒有valueOf()方法,或者這個方法不返回一個原始值,那麼JavaScript會調用toString()方法。如果這個方法存在JavaScript則會調用它。如果返回值是原始值,JavaScript會將這個值轉換爲數字(如果其本身不是數字的話),並返回這個數字。
3、否則, 無法從toString()或valueOf()獲得一個原始值。因此這時將拋出一個類型錯誤異常。
3 “==”與“===”
在講述各類型比較之前,我們先了解一下“==”(相等運算符)與“===”(恆等運算符)
3.1 “===”
嚴格相等運算符“===”,也稱做恆等運算符,它用來檢測兩個操作數是否嚴格相等。
恆等運算符“===”,首先比較兩個操作數數據類型是否相同,然後比較這兩個值,比較過程中沒有任何類型轉換:
(1) 如果兩個值類型不同,則它們不同。
(2)如果兩個值都是null或者都是undefined,則他們相等。
(3)如果兩個值都是布爾值true或者都是false,則他們相等。
(4)如果其中一個值是NaN,或者兩個值都是NaN,則他們不相等。NaN和其他任何值都不相等,包含它本身。通過x!==x判斷x是否爲NaN,只有當x爲NaN時,這個表達式才爲true。
(5)如果兩個值都爲數字且數值相等,則它們相等。如果一個值是0,另一個值是-0,它們同樣相等。
(6)如果兩個值爲字符串,且所含對應爲上的16位 數完全相等,則他們相等。如果他們的長度或內容不同,則它們不相等。兩個字符串可能完全意義上一樣且顯示出的字符也一樣,但是具有不同編碼的16位值,則他們不等。
(7)如果兩個引用值指向同一個對象、數組、函數,則他們相等。如果指向不同的對象,則他們不等,儘管兩個對象具有完全一樣的屬性。
3.2 “==”
相等運算符“==”,用來檢測兩個操作數是否相等,不同意恆等運算符“===”的是,相等運算符“==”,只比較兩個操作數的值是否相等,如果兩個操作數的數據類型不同,那麼相等運算符“==”會嘗試做做隱式類型轉換,然後進行比較。
(1)如果兩個數據類型相同,則和恆等運算符所述規則一樣。如果嚴格相等,那麼比較結果相等,如果不嚴格相等,則比較結果爲不相等。
(2)如果兩個操作數的數據類型不同,相等運算符“==”也可能認爲他們相等。檢查相等會遵循如下規則和類型轉換:
①如果一個值是null,另一個是undefined,則他們相等。
②如果一個值是數字,另一個值是字符串,則先將字符串轉換爲數字,然後使用轉換後的值進行比較
③如果其中一個值是true,則將其轉換成1再進行比較。如果其中一個值是false,則將其轉換成0再進行比較。
④如果一個值是對象,另一個值是數字或字符串,則現將對象轉換成原始值(轉換規則如上述),然後進行比較。
⑤其他不同類型之間的比較不相等。
3.3 總結
恆等運算符“===”
數據類型相同時:
原始值直接比較值,值相等則他們相等,需要注意的是String類型必須具有相同編碼的16位值。
引用類型,需要注意是否指向同一個對象、數組、函數。Eg: var a = [1,2,3];var b = [1,2,3]; a === b; 結果爲false。
var a = [1,2,3];
var b = [1,2,3];
alert("a === b:" + (a === b));
數據類型不同時:直接返回false;
相等運算符“==”
數據類型相同時,比較結果與恆等運算符比較結果相同。
數據類型不同時:
(1)null與undefined除與自己相等外,他們彼此也相等,即 null == undefined,結果返回爲true。
(2)如果都是原始值,會將其他類型轉換爲數字,然後進行比較。
(3)如果其中一個類型是對象,則將對象轉換爲原始值,然後在進行比較。
....未完