JavaScript中對象轉換為原始值遵循哪些原則? P52
對象到布爾值
對象到布爾值的轉換非常簡單:所有的對象(包括數字和函數)都轉換為true。對於包裝對象亦是如此:new Boolean(false)是一個對象而不是原始值,它將轉換為true。
對象到字符串
對象到字符串(object-to-string)和對象到數字(object-to-number)的轉換都是通過調用待轉換對象的一個方法來完成的。一個麻煩的事實是,JavaScript對象有兩個不同的方法來執行轉換,並且借來帶要討論的一些特殊場景更加復雜。值得注意的是,這里提到的字符串和對象的轉換規則只適用於本地對象(native object)。宿主對象(例如有Web瀏覽器定義的對象)根據各自的算法可以轉換成字符串和數字。
所有的對象繼承了兩個轉換方法。第一個是toString(),它的作用是返回一個反映這個對象的字符串。默認的toString()方法並不會返回一個有趣的值:
1 ({x:1,y:2}).toString() //=>"[object object]"
[擴展閱讀:JavaScript中的toString()方法 ]
很多類定義了更多特定版本的toString()方法。例如,數組類(Array class)的toString()方法將每個數組元素轉換為一個字符串,並在元素之間添加逗號后合並成結果字符串。函數類(Function class)的toString()方法返回了這個函數的實現定義的表示方式。實際上,這里的實現是通常是將用戶定義的函數轉換為JavaScript源代碼字符串。日期類(Date class)定義的toString()方法返回了一個可讀的(可被JavaScript解析的)日期和時間字符串。RegExp類(RegExp class)定義的toString()方法將RegExp對象轉換為表示正則表達式直接量的字符串:
1 [1,2,3].toString()//=>"1,2,3" 2 (function(x){ f(x); }).toString()//=>"function(x){\nf{x);\n}}" 3 /\d+/g.toString() //=>" /\d+/g" 4 new Date(2010,0,1).toString() //=>"Fri Jan 01 2010 00:00:00 GMT-0800
另一個轉換對象的函數是valueOf()。這個方法的任務並未詳細定義:如果存在任意原始值,它就默認將對象轉換為表示它的原始值。對象是復合值,而且大多數對象無法真正表示為一個原始值,因此默認的valueOf()方法簡單地返回對象本身,而不是返回一個原始值。數組、函數和正則表達式簡單地繼承了這個方法,調用這些類型的實例的valueOf()方法只是簡單返回對象本身。日期類定義的valueOf()方法會返回它的一個內部表示:1970年1月1日以來的毫秒數。
[擴展閱讀:JavaScript中的valueOf()方法 ]
1 var d=new Date(2010,0,1);//=>2010年1月1日(太平洋時間) 2 d.valueOf();//=>1262332800000
通過使用toString()和valueOf()方法,就可以做到對象到字符串和對象到數字的轉換了。但需要注意的是,在某些特殊的場景中,JavaScript執行了完全不同的對象到原始值的轉換。
JavaScript中對象到字符串的轉換經過如下這些步驟:
- 如果對象具有toString()方法,則調用這個方法。如果它返回一個原始值,JavaScript將這個值轉換為字符串(如果本身不是字符串的話),並返回這個字符串結果。需要注意,原始值到字符串的轉換。
- 如果對象沒有toString()方法,或者這個方法並不返回一個原始值,那么JavaScript會調用valueOf()方法。如果存在這個方法,則JavaScript調用它。如果返回值是原始值,JavaScript將這個值轉換為字符串(如果本身不是字符串的話),並返回這個字符串結果。
- 否則,JavaScript無法從toString()或valueOf()獲得一個原始值,因此這時它將拋出一個類型錯誤異常。
在對象到數字的轉換過程中,JavaScript做了同樣的事情,只是它會首先嘗試使用valueOf()方法:
- 如果對象具有valueOf()方法,后者返回一個原始值,則JavaScript將這個原始值轉換為數字(如果需要的話),並返回這個數字。
- 否則,如果對象具有toString()方法,后者返回一個原始值,則JavaScript將其轉換並返回。
- 否則,JavaScript拋出一個類型錯誤異常。
對象轉換為數字的細節解釋了為什么空數組會被轉換為數字0以及為什么具有單個元素的數組同樣會轉換成一個數字。數組繼承了默認的valueOf()方法。這個方法返回了一個對象而不是一個原始值,因此,數組到數字的轉換則調用toString()方法。空數組轉換成為空字符串,空字符串轉換成為數字0。含有一個元素的數組轉換為字符串的結果和這個元素轉換字符串的結果一樣。如果數組只包含一個數字元素,這個數字轉換為字符串,再轉換回數字。
JavaScript中的+運算符可以進行數學加法和字符串連接操作。如果它的其中一個操作數是對象,則JavaScript將使用特殊的方法將對象轉換成為原始值,而不是使用其他算術運算符的方法執行對象到數字的轉換。
+和==應用的對象到原始值的轉換包含日期對象的一種特殊情形。日期類是JavaScript語言核心中唯一的預先定義類型,它定義了有意義的向字符串和數字類型的轉換。對於所有非日期的對象來說,對象到原始值的轉換基本上是對象到數字的轉換(首先調用valueOf()),日期對象則使用對象到字符串的轉換模式,然而,這里的轉換和上文講述的並不完全一致:通過valueOf()或toString()返回的原始值將被直接使用,而不會被強制轉換為數字或字符串。
和==一樣,<運算符以及其他關系運算符也會做對象到原始值的轉換,但要除去日期對象的特殊情形:任何對象都會首先嘗試調用valueOf(),然后調用toString()。不管得到的原始值是否直接使用,它都不會進一步被轉換為數字或字符串。
“+”、“==”、“!=”和關系運算符是唯一執行這種特殊的字符串到原始值的轉換方式的運算符。其他運算符到特定類型的轉換都很明確,而且對日期對象來講也沒有特殊情況。例如“-”(減號)運算符把它的兩個操作數都轉換為數字。下面的代碼展示了日期對象和“+”、“-”、“==”以及“>”的運行結果:
var now =new Date();//創建一個日期對象 typeof(now+1); //=>"string":“+”將日期轉換為字符串 typeof(now-1);//=>"number":"-"使用對象到數字的轉換 now== now.toString(); //=>true:隱式的和顯示的字符串轉換 now>(now-1);//=>true:">"將日期轉換為數字