JS資料型別的轉換

kari發表於2019-04-03

JavaScript 是一種動態型別語言,變數沒有型別限制,可以隨時賦予任意值。

var x = y ? 1 : 'a'
複製程式碼

上面程式碼中,變數 x 到底是數值還是字串,取決於另一個變數 y 的值。

ytrue 時,x 是一個數值;yfalse 時,x 是一個字串。這意味著,x 的型別沒法在編譯階段就知道,必須等到執行時才能知道。

轉換為 Number 型別

使用 Number() 函式,可以將任意型別的值轉化成數值。

下面分成兩種情況討論,一種是引數是原始型別的值,另一種是引數是物件。

原始型別值

原始型別值的轉換規則:

// 數值:轉換後還是原來的值
Number(324)  // 324

// 字串:如果可以被解析為數值,則轉換為相應的數值
Number('324')  // 324

// 字串:如果不可以被解析為數值,返回 NaN
Number('324abc')  // NaN

// 空字串轉為0
Number('')  // 0

// 布林值:true 轉成 1,false 轉成 0
Number(true)  // 1
Number(false)  // 0

// undefined:轉成 NaN
Number(undefined)  // NaN

// null:轉成0
Number(null)  // 0
複製程式碼

Number() 函式將字串轉為數值,要比 parseInt() 函式嚴格很多。基本上,只要有一個字元無法轉成數值,整個字串就會被轉為 NaN

parseInt('42 cats')  // 42
Number('42 cats')  // NaN
複製程式碼

上面程式碼中,parseInt() 逐個解析字元,而 Number() 函式整體轉換字串的型別。

另外,parseInt()Number() 函式都會自動過濾一個字串前導和字尾的空格。

parseInt('\t\v\r12.34\n')  // 12
Number('\t\v\r12.34\n')  // 12.34
複製程式碼

使用 parseInt() 函式 在使用時要注意:

// 將二進位制的'1000'轉為十進位制的數值
parseInt('1000', 2)  // 8
複製程式碼

物件

Number() 方法的引數是物件時,將返回 NaN,除非是包含單個數值的陣列。

Number({a: 1}) // NaN
Number([1, 2, 3]) // NaN
Number([5]) // 5
複製程式碼

之所以會這樣,是因為 Number() 背後的轉換規則比較複雜。

  • 呼叫物件自身的 valueOf() 方法。如果返回原始型別的值,則直接對該值使用 Number() 函式,不再進行後續步驟。

  • 如果 valueOf() 方法返回的還是物件,則改為呼叫物件自身的 toString() 方法。如果 toString() 方法返回原始型別的值,則對該值使用 Number() 函式,不再進行後續步驟。

  • 如果 toString() 方法返回的是物件,就報錯。

請看下面的例子:

var obj = {x: 1};
Number(obj) // NaN

// 等同於
if (typeof obj.valueOf() === 'object') {
  Number(obj.toString());
} else {
  Number(obj.valueOf());
}
複製程式碼

上面程式碼中,Number() 函式將 obj 物件轉為數值。背後發生了一連串的操作,首先呼叫 obj.valueOf() 方法, 結果返回物件本身;於是,繼續呼叫 obj.toString() 方法,這時返回字串 [object Object] ,對這個字串使用 Number() 函式,得到 NaN

預設情況下,物件的 valueOf() 方法返回物件本身,所以一般總是會呼叫 toString() 方法,而 toString() 方法返回物件的型別字串(比如 [object Object] )。所以,會有下面的結果。

Number({}) // NaN
複製程式碼

如果 toString() 方法返回的不是原始型別的值,結果就會報錯。

var obj = {
  valueOf: function () {
    return {}
  },
  toString: function () {
    return {}
  }
}

Number(obj)
// TypeError: Cannot convert object to primitive value
複製程式碼

上面程式碼的valueOf()toString() 方法,返回的都是物件,所以轉成數值時會報錯。

轉換為 String 型別

使用 String() 函式,可以將任意型別的值轉化成字串。

下面分成兩種情況討論,一種是引數是原始型別的值,另一種是引數是物件。

原始型別值

原始型別值的轉換規則:

// 數值:轉為相應的字串
String(123)  // "123"

// 字串:轉換後還是原來的值
String('abc')  // "abc"

// 布林值:true 轉為字串"true"false轉為字串"false"
String(true)  // "true"

// undefined:轉為字串"undefined"
String(undefined)  // "undefined"

// null:轉為字串"null"
String(null)  // "null"
複製程式碼

物件

String() 方法的引數如果是物件,返回一個型別字串;如果是陣列,返回該陣列的字串形式。

String({a: 1}) // "[object Object]"
String([1, 2, 3]) // "1,2,3"
複製程式碼

String()方法背後的轉換規則,與Number方法基本相同,只是互換了 valueOf() 方法和 toString() 方法的執行順序。

  • 先呼叫物件自身的 toString() 方法。如果返回原始型別的值,則對該值使用 String() 函式,不再進行以下步驟。

  • 如果 toString() 方法返回的是物件,再呼叫原物件的 valueOf() 方法。如果 valueOf() 方法返回原始型別的值,則對該值使用 String() 函式,不再進行以下步驟。

  • 如果 valueOf() 方法返回的是物件,就報錯。

下面是一個例子:

String({a: 1})
// "[object Object]"

// 等同於
String({a: 1}.toString())
// "[object Object]"
複製程式碼

上面程式碼先呼叫物件的 toString() 方法,發現返回的是字串 [object Object],就不再呼叫 valueOf() 方法了。

轉換為 Boolean 型別

使用 Boolean() 函式,可以將任意型別的值轉化成布林值。

它的轉換規則相對簡單:除了以下五個值的轉換結果為 false,其他的值全部為 true

  • -0+0
  • NaN
  • ''""(空字串)
  • null
  • undefined
Boolean(0) // false
Boolean(NaN) // false
Boolean('') // false
Boolean(null) // false
Boolean(undefined) // false
複製程式碼

注意,所有物件(包括空物件)的轉換結果都是 true,甚至連 false 對應的布林物件 new Boolean(false) 也是 true

Boolean({}) // true
Boolean([]) // true
Boolean(new Boolean(false)) // true
複製程式碼

相關文章