JavaScript中物件轉換為原始值的步驟
首先附加一張JavaScript型別轉換表
值 | 轉換為字串 | 數字 | 布林值 | 物件 |
undefined | “undefined” | NaN | false | throws TypeError |
null | “null” | 0 | false | throws TypeError |
true | “true” | 1 | true | new Boolean(true) |
false | “false” | 0 | false | new Boolean(false) |
“” | “” | 0 | false | new String(“”) |
“1.2” | “1.2” | 1.2 | true | new String(“1.2”) |
“zero” | “zero” | NaN | true | new String(“zero”) |
0 | “0” | 0 | false | new Number(0) |
-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(無窮大,非零) | “1” | true | new Number(1) | |
{}(任意物件) | 物件本身 | 物件本身 | true | new Object({}) |
[] (陣列) | “” | 0 | true | new Array() |
[0] (陣列) | “0” | 0 | true | new Array() |
[0,1,2] (陣列) | “0,1,2” | NaN | true | new Array() |
function(){} | 函式本身 | NaN | true |
在JavaScript中物件到布林型別的轉換非常簡單,所有的物件(包括陣列和函式)都轉換為true。對於包裝物件也是如此。注意:new Boolean(false) 是一個物件而不是原始值,它將轉換為true。
物件轉換為字串和物件轉換為數字的轉換時通過呼叫待轉換物件的一個方法來完成的。在JavaScript物件有兩個不同的方法來執行轉換,並且接下來要討論的一些場景比較複雜。需要注意的是,這裡提到的字串和數字的轉換規則只使用本地物件(native object)。宿主物件(Web瀏覽器定義的物件)根據各自的演算法可以轉換成字串和數字。
所有物件都繼承了兩個轉換方法:toString()和valueOf。 toString()的作用是返回這個物件的字串。例如:
console.log(({x:0,y:1}).toString());//輸出"[object object]"
很多類定義了更多特定版本的toString()方法。例如,陣列類(Array class) 的toString()方法把陣列中的每個元素轉換為用逗號合併的字串。例如:
console.log([1,2,3].toString());//輸出1,2,3
函式類(Function class)的toString()方法返回這個函式實現定義的方式。也就是說將使用者定義的函式轉換為JavaScript原始碼字串。例如:
console.log((function(x){f(x);}).toString());//輸出"function(x){f(x);}"
日期類(Date class)的toString()方法返回一個可被JavaScript解析的日期和時間字串。例如:
console.log(new Date(2017,1,14).toString());//輸出Tue Feb 14 2017 00:00:00 GMT+0800 (中國標準時間)
正則類(RegExp class)的toString()把正則物件轉換正則表達的字串格式。例如:
var pattern=/\d+/g;
console.log(pattern.toString());///\d+/g
valueOf()方法的任務並未詳細定義:如果存在任意的原始值,它就預設將物件轉換為它的原始值。物件時複合值而且大多數物件無法真正表示一個原始值,因此預設valueOf()方法簡單地返回物件本身,而不是返回一個原始值。陣列、函式、正則表示式都繼承了這個預設方法,呼叫這些型別例項的valueOf()方法只是返回物件本身。日期類物件的valueOf()方法一個它的內部表示,從1970年1月1日以來總的毫秒數。 例如:
console.log(({x:0,y:1}).valueOf());//輸出Object {x: 0, y: 1}
console.log([1,2,3].valueOf());//輸出 [1, 2, 3]
console.log((function(x){f(x);}).valueOf());//輸出function (x){f(x);}
var d=new Date(2017,1,14);
console.log(d.valueOf());//1487001600000
var n=new Number(1);
console.log(n.valueOf());//輸出1
var b=new Boolean(false);
console.log(b.valueOf());//輸出false
var str=new String("str");
console.log(str.valueOf());//輸出str
需要注意的特殊轉換:
var n=new Number("a");
console.log(n.valueOf());//NaN
var b=new Boolean("str");
console.log(b.valueOf());//輸出true
通過上面的介紹的toString()和valueOf()方法,就可以做到物件到字串和物件到數字的轉換了。但需要注意的是某些特殊場景(+、-、*、==、!= 、>、<)中JavaScript執行了完全不同的物件到原始值的轉換。
總的而言,在JavaScript中物件到字串的轉換經過如下步驟:
1) 如果物件具有toString()方法,則呼叫這個方法。如果返回一個原始值,JavaScript將這個值轉換字串,並返回這個字串的結果。
2)如果物件沒有toString()方法或者這個方法並不是返回一個原始值,那麼JavaScript會呼叫valueOf()方法。如果存在這個方法,JavaScript呼叫它。如果返回值是原始值,將這個值轉換為字串,然後返回。
3)如果無法從toString()和valueOf()獲得一個原始值,此時就會丟擲一個型別錯誤。
在物件到數字的轉換過程中,JavaScript做了同樣的事情,只是它首先嚐試呼叫valueOf()方法。
1)如果物件具有valueOf()方法,並返回一個原始值,則JavaScript將這個原始值轉換為數字,並返回這個數字。
2) 否則,物件嘗試去呼叫toString()方法,返回一個原始值,則JavaScript返回這個值。
3)如果無法從valueOf()和toString()獲得一個原始值,此時就會丟擲一個型別錯誤。
物件轉換數字的細節解釋了為什麼空陣列會被轉換為數字0以及為什麼具有單個元素的陣列會被轉換為一個數字。陣列繼承了預設的valueOf()方法,這個方法返回一個物件而不是一個原始值,因此陣列到陣列的轉換呼叫toString()方法。空陣列轉換成空字串,空字串轉換為數字0。含有一個元素的陣列轉換為字串的結果和這個元素轉換字串的結果一樣。如果陣列只包含一個數字元素,這個數字轉換為字串,再轉換為數字。
JavaScript中的”+”運算子可以進行數學加法和字串連線操作。如果它的其中一個操作是物件,則JavaScript將使用特殊的方法將物件轉換為原始值,而不是使用其它算術運算子的方法執行物件到數字的轉換。”==”相等運算子與此類似。如果將物件和一個原始值比較,則轉換將會遵照物件到原始值得轉換方式進行。
“+”和”==”應用的物件到原始值得轉換包含日期物件的一種特殊情形。日期類是JavaScript語言核心中唯一的預先定義型別,它定義了有意義的向字串和數字型別的轉換。對於所有非日期的物件來說,物件到原始值的轉換基本上是物件到數字的轉換(首先呼叫valueOf),日期物件則使用物件到字串的轉換模。然而這裡的轉換(+ ==)和上文講述的並不完全一致:通過valueOf和toString 返回的原始值將被直接使用,而不會被強制轉換為數字或者字串。
和”==”一樣,”<”運算子以及其它關係算術運算子也會做到物件到原始值得轉換,但要除去日期物件的特殊情形:任何物件都會先嚐試呼叫valueOf,然後呼叫toString。不管得到的原始值是否直接使用,它都不會進一步被轉換為數字或字串。
“+”、”==”、”!=”和關係運算符是唯一執行特殊的字串到原始值的轉換方式的運算子。其它運算子到特定型別的轉換很明確,而且對日期物件來講也沒有特殊情況。例如”-“運算子把它的兩個運算元都轉換為數字。下面演示日期物件、”+”、”-“、”==”、”>”的結果:
var now=new Date();
console.log(typeof (now+1));//string +號把日期轉換為字串
console.log(typeof (now-1));//number -號把物件到數字的轉換
console.log(now==now.toString());//true
console.log(now>now-1);//true >把日期轉換為數字
文章參考來源:《JavaScript 權威指南》(原書第六版) 作者 弗蘭納根