「譯」JavaScript 的怪癖 1:隱式型別轉換

迷渡發表於2013-04-18

原文:JavaScript quirk 1: implicit conversion of values

譯文:「譯」JavaScript 的怪癖 1:隱式型別轉換

譯者:justjavac


零:提要

[此貼子是 javascript 的 12 個怪癖(quirks) 系列的第一篇。]

JavaScript 是非常寬容的,「來者不拒」,不在乎什麼型別。 例如,它如果想要接受數字,它並不拒絕其他型別的值,而是試圖把它們轉換成數字:

> '5' - '2'
3
> '5' * '2'
10

自動轉換為布林值通常不會引起問題,而且往往很有用(譯註:比如在C語言裡,根本就沒有布林型別。by @justjavac)。 即使如此,這些隱式轉換也會引起怪癖(quirks)。 但是當自動轉換為字串時,可能會引起問題。

一:隱式轉換為布林:“truthy”和“falsy”

當 JavaScript 需要一個布林值時(例如:if 語句),任何值都可以被使用。 最終這些值將被轉換為 true 或 false

下面的值被轉換為 false

  • undefined, null
  • Boolean: false
  • Number: -0, +0, NaN
  • String: ''

所有其他值都認為是 true。 被轉換成 'false' 的值我們成之為 falsy,被轉換成 'true' 的值我們成之為 truthy。 您可以使用 Boolean 來測試一個值到底被轉換成了什麼。

Boolean 將其引數轉換為布林值(boolean):

> Boolean(undefined)
false
> Boolean(0)
false
> Boolean(3)
true

二、字串的隱式轉換

在 Web 開發中,我們經常得到字串值,實際上我們期望的卻是數字或者布林值。 例如,使用者輸入的表單中的資料。 如果你忘了對這些字串進行顯式的轉換,那麼 JavaScript 會令你感到驚訝,主要體現在兩個方面:

  1. 首先,系統不會有任何警告。
  2. 其次,這些值將被自動轉換,但確實錯誤的。

例如,加運算子(+),就有這方面的問題,因為**只要其中一個運算元是字串,那麼它就執行連線字串的操作(而不是加法操作,即使它們是數字)**。

在下面的 JavaScript 程式碼中,我們本來預期是把 1 和 5 相加。 但是,我們使用了字串 '5' 和 '1' 。

> var x = '5';  // 錯誤的假設:x 是一個數字

> x + 1
'51'

此外,還有一些看似是 false 的值,如果轉換成字串,卻成了 'true'。

例如:false

> Boolean(false)
false
> String(false)
'false'
> Boolean('false')  // !!
true

例如: undefined.

> Boolean(undefined)
false
> String(undefined)
'undefined'
> Boolean('undefined')  // !!
true

三、物件的隱式轉換

只有在 JavaScript 表示式或語句中需要用到數字或字串時,物件才被隱式轉換。 當需要將物件轉換成數字時,需要以下三個步驟:

  1. 呼叫 valueOf()。如果結果是原始值(不是一個物件),則將其轉換為一個數字。
  2. 否則,呼叫 toString() 方法。如果結果是原始值,則將其轉換為一個數字。
  3. 否則,丟擲一個型別錯誤。

第一步示例:

> 3 * { valueOf: function () { return 5 } }
15

第三步示例:

> function returnObject() { return {} }
> 3 * { valueOf: returnObject, toString: returnObject }
TypeError: Cannot convert object to primitive value

如果把物件轉換成字串時,則轉換操作的第一步和第二步的順序會調換: 先嚐試 toString() 進行轉換,如果不是原始值,則再嘗試使用 valueOf()

四、相關閱讀

  1. JavaScript中,{}+{}等於多少?
  2. JavaScript:將所有值都轉換成物件
  3. 為什麼 ++[[]][+[]]+[+[]] = 10?

相關文章