天天看點

js筆記——js資料類型轉換

javascript是一種動态類型語言,變量是沒有類型的,可以随時賦予任意值。但是,資料本身和各種運算是有類型的,是以運算時變量需要轉換類型。大多數情況下,這種資料類型轉換是自動的,但是有時也需要手動強制轉換。

強制轉換主要指使用number、string和boolean三個構造函數,手動将各種類型的值,轉換成數字、字元串或者布爾值。

使用number函數,可以将任意類型的值轉化成數字。

(1)原始類型值的轉換規則

數值:轉換後還是原來的值。

字元串:如果可以被解析為數值,則轉換為相應的數值,否則得到nan。空字元串轉為0。

布爾值:true轉成1,false轉成0。

undefined:轉成nan。

null:轉成0。

number函數将字元串轉為數值,要比parseint函數嚴格很多。基本上,隻要有一個字元無法轉成數值,整個字元串就會被轉為nan。

上面代碼比較了number函數和parseint函數,差別主要在于parseint逐個解析字元,而number函數整體轉換字元串的類型。另外,number會忽略八進制的前導0,而parseint不會。

number函數會自動過濾一個字元串前導和字尾的空格。

(2)對象的轉換規則

對象的轉換規則比較複雜。

先調用對象自身的valueof方法,如果該方法傳回原始類型的值(數值、字元串和布爾值),則直接對該值使用number方法,不再進行後續步驟。

如果valueof方法傳回複合類型的值,再調用對象自身的tostring方法,如果tostring方法傳回原始類型的值,則對該值使用number方法,不再進行後續步驟。

如果tostring方法傳回的是複合類型的值,則報錯。

上面代碼等同于

上面代碼的valueof方法傳回對象本身({a:1}),是以對tostring方法的傳回值“[object object]”使用number方法,得到nan。

如果tostring方法傳回的不是原始類型的值,結果就會報錯。

上面代碼的valueof和tostring方法,傳回的都是對象,是以轉成數值時會報錯。

從上面的例子可以看出,valueof和tostring方法,都是可以自定義的。

上面代碼對三個對象使用number方法。第一個對象傳回valueof方法的值,第二個對象傳回tostring方法的值,第三個對象表示valueof方法先于tostring方法執行。

使用string函數,可以将任意類型的值轉化成字元串。規則如下:

數值:轉為相應的字元串。

字元串:轉換後還是原來的值。

布爾值:true轉為“true”,false轉為“false”。

undefined:轉為“undefined”。

null:轉為“null”。

如果要将對象轉為字元串,則是采用以下步驟。

先調用tostring方法,如果tostring方法傳回的是原始類型的值,則對該值使用string方法,不再進行以下步驟。

如果tostring方法傳回的是複合類型的值,再調用valueof方法,如果valueof方法傳回的是原始類型的值,則對該值使用string方法,不再進行以下步驟。

如果valueof方法傳回的是複合類型的值,則報錯。

string方法的這種過程正好與number方法相反。

上面代碼相當于下面這樣。

如果tostring方法和valueof方法,傳回的都不是原始類型的值,則string方法報錯。

下面是一個自定義tostring方法的例子。

上面代碼對三個對象使用string方法。第一個對象傳回tostring方法的值(數值3),然後對其使用string方法,得到字元串“3”;

第二個對象傳回的還是tostring方法的值("[object

object]"),這次直接就是字元串;第三個對象表示tostring方法先于valueof方法執行。

使用boolean函數,可以将任意類型的變量轉為布爾值。

(1)原始類型值的轉換方法

以下六個值的轉化結果為false,其他的值全部為true。

undefined

null

-0

nan

''(空字元串)

所有對象的布爾值都是true,甚至連false對應的布爾對象也是true。

請注意,空對象{}和空數組[]也會被轉成true。

當遇到以下幾種情況,javascript會自動轉換資料類型:

不同類型的資料進行互相運算;

對非布爾值類型的資料求布爾值;

對非數值類型的資料使用一進制運算符(即“+”和“-”)。

當javascript遇到預期為布爾值的地方(比如if語句的條件部分),就會将非布爾值的參數自動轉換為布爾值。它的轉換規則與上面的“強制轉換成布爾值”的規則相同,也就是說,在預期為布爾值的地方,系統内部會自動調用boolean方法。

是以除了以下六個值,其他都是自動轉為true:

當javascript遇到預期為字元串的地方,就會将非字元串的資料自動轉為字元串,轉換規則與“強制轉換為字元串”相同。

字元串的自動轉換,主要發生在加法運算時。當一個值為字元串,另一個值為非字元串,則後者轉為字元串。

當javascript遇到預期為數值的地方,就會将參數值自動轉換為數值,轉換規則與“強制轉換為數值”相同。

除了加法運算符有可能把運算子轉為字元串,其他運算符都會把兩側的運算子自動轉成數值。

上面都是二進制算術運算符的例子,javascript的兩個一進制算術運算符——正号和負号——也會把運算子自動轉為數值。

由于自動轉換有很大的不确定性,而且不易除錯,建議在預期為布爾值、數值、字元串的地方,全部使用boolean、number和string方法進行顯式轉換。

加法運算符(+)需要特别讨論,因為它可以完成兩種運算(加法和字元連接配接),是以不僅涉及到資料類型的轉換,還涉及到确定運算類型。

加法運算符的類型轉換,可以分成三種情況讨論。

(1)運算子之中存在字元串

兩個運算子之中,隻要有一個是字元串,則另一個不管是什麼類型,都會被自動轉為字元串,然後執行字元串連接配接運算。前面的《自動轉換為字元串》一節,已經舉了很多例子。

(2)兩個運算子都為數值或布爾值

這種情況下,執行加法運算,布爾值轉為數值(true為1,false為0)。

(3)運算子之中存在對象

運算子之中存在對象(或者準确地說,存在非原始類型的值),則先調用該對象的valueof方法。如果傳回結果為原始類型的值,則運用上面兩條規則;否則繼續調用該對象的tostring方法,對其傳回值運用上面兩條規則。

上面代碼的運作順序是,先調用[1,2].valueof(),結果還是數組[1,2]本身,則繼續調用[1,2].tostring(),結果字元串“1,2”,是以最終結果為字元串“11,2”。

對象{a:1}的valueof方法,傳回的就是這個對象的本身,是以接着對它調用tostring方法。({a:1}).tostring()預設傳回字元串"[object object]",是以最終結果就是字元串“1[object object]”

有趣的是,如果更換上面代碼的運算次序,就會得到不同的值。

原來此時,javascript引擎不将{a:1}視為對象,而是視為一個代碼塊,這個代碼塊沒有傳回值,是以被忽略。是以上面的代碼,實際上等同于 {a:1};+1 ,是以最終結果就是1。為了避免這種情況,需要對{a:1}加上括号。

将{a:1}放置在括号之中,由于javascript引擎預期括号之中是一個值,是以不把它當作代碼塊處理,而是當作對象處理,是以最終結果為“[object object]1”。

上面代碼的valueof方法傳回數值2,是以最終結果為3。

上面代碼的valueof方法傳回一個空對象,則繼續調用tostring方法,是以最終結果是“1[object object]”。

上面代碼的tostring方法傳回數值2(不是字元串),則最終結果就是數值3。

上面代碼的tostring方法傳回一個空對象,javascript就會報錯,表示無法獲得原始類型的值。

有了上面這些例子,我們再進一步來看四個特殊表達式。

(1)空數組 + 空數組

首先,對空數組調用valueof方法,傳回的是數組本身;是以再對空數組調用tostring方法,生成空字元串;是以,最終結果就是空字元串。

(2)空數組 + 空對象

這等同于空字元串與字元串“[object object]”相加。是以,結果就是“[object object]”。

(3)空對象 + 空數組

javascript引擎将空對象視為一個空的代碼塊,加以忽略。是以,整個表達式就變成“+ []”,等于對空數組求正值,是以結果就是0。轉化過程如下:

如果javascript不把前面的空對象視為代碼塊,則結果為字元串“[object object]”。

(4)空對象 + 空對象

javascript同樣将第一個空對象視為一個空代碼塊,整個表達式就變成“+

{}”。這時,後一個空對象的valueof方法得到本身,再調用tosting方法,得到字元串“[object

object]”,然後再将這個字元串轉成數值,得到nan。是以,最後的結果就是nan。轉化過程如下:

如果,第一個空對象不被javascript視為空代碼塊,就會得到“[object object][object object]”的結果。

需要指出的是,對于第三和第四種情況,node.js的運作結果不同于浏覽器環境。

可以看到,node.js沒有把第一個空對象視為代碼塊。原因是node.js的指令行環境,内部執行機制大概是下面的樣子:

node.js把指令行輸入都放在eval中執行,是以不會把起首的大括号了解為空代碼塊加以忽略。

繼續閱讀