JavaScript隱式類型轉換

JavaScript隱式類型轉換

基本數據類型

ECMAScript 一共定義了七種 build-in types,其中六種爲 Primitive ValueNullUndefinedStringNumberBooleanSymbol。而最後一種 Object build-in type 與一般意義上的 JavaScript 中 Object 並不同,總的來講,只要不屬於 Primitive Value 的值,就屬於 Object 類型,好比數組、對象、日期、正則、函數。javascript

裝箱轉換

每一種基本類型 number, string, boolean, symbolObject(build-in type) 中都有對應的類。所謂裝箱轉換,正是把基本類型轉換爲對應的對象,他是類型轉換中一種至關重要的種類。html

JavaScript 語言設計上試圖模糊對象和基本類型之間的關係,好比,咱們能夠直接在基本類型上使用對象的方法:java

console.log('abc'.charAt()); // a

甚至咱們在原型上添加方法,均可以應用於基本類型。git

其實是 . 運算符提供了裝箱操做,它會根據基礎類型構造一個臨時對象,使得咱們能在基礎類型上調用對應對象的方法。github

拆箱轉換

在 JavaScript 標準中,規定了 ToPrimitive 函數,它是對象類型到基本類型的轉換(即,拆箱轉換)。segmentfault

對象到 String 和 Number 的轉換都遵循「先拆箱再轉換」的規則。經過拆箱轉換,把對象變成基本類型,再從基本類型轉換爲對應的 String 或者 Number。數組

拆箱轉換會嘗試調用 valueOf 和 toString 來得到拆箱後的基本類型。若是 valueOf 和 toString 都不存在,或者沒有返回基本類型,則會產生類型錯誤 TypeError。函數

ToPrimitive

ToPrimitive 用於將 Object 轉爲 Primitive Valueui

對於咱們日常遇到的 Object,其處理邏輯是:設計

  • 調用 Object.valueOf,若是結果是 Primitive Value,則返回;
  • 調用 Object.toString,若是結果是 Primitive Value,則返回;
  • 都不是,返回 TypeError

普通對象和數組的這兩個方法返回的結果以下:

var a = [12]
var b = {a: 123}

// [12]
a.valueOf()

// '12'
a.toString()

// {a: 123}
b.valueOf()

// '[object Object]'
b.toString()

如上,二者的 valueOf 返回的都不是 Primitive Value (返回了自身,仍是 Object 類型)。那麼,根據規範,二者調用 ToPrimitive 返回的將是一個 字符串

顯示類型轉換

ToBoolean

這個方法用於將不是 Boolean 類型的值轉換爲 Boolean 類型。

  • Undefined 返回 false
  • Null 返回 false
  • 全部 Object 類型都會被轉換爲 true;
  • Number 類型中,0,NaN 會被轉換爲 false,其它都爲 true
  • 只有空字符串爲 false,其它都爲 true

ToNumber

其它類型轉換爲 Number 類型。

  • Undefined 返回 NaN
  • Null 返回 0
  • Boolean 類型,true 爲 1; false 爲 0
  • String 類型,若是知足數字語義則轉爲數字,不然轉換爲 NaN
  • Object 類型,先轉換爲 Primitive Value 再遞歸調用自身 ToNumber 來轉換。
// '56' ==> 56
Number([56])

// ',56' ==> NaN
Number([,56])

// '55,56' ==> NaN
Number([55, 56])

ToString

  • Number 返回 對應數值字符串
  • Boolean 返回字符串 「true」 或者 「false」
  • Undefined 返回 「undefined」
  • Null 返回 「null」

隱式類型轉換

瞭解了上面的知識,能夠開始進入咱們的正題了,在 JavaScript 中能夠觸發隱式類型轉換的操做有:

  • 四則運算: +, -, *, /
  • 比較運算符: ==, <, >, >=, <=
  • 判斷語句: if, while
  • Native調用: console, alet 輸入時會自動轉換成 String 類型
  • 邏輯非 !,將直接調用 ToBoolean 方法,而後取反返回。

比較運算符

非嚴格比較(==)

  • 若是 Type 相同,等價於 A === B
  • 特別的, undefined == null
  • String == Number,則把 String 轉換成 Number
  • Boolean 值的,將 Boolean 轉換成 Number
  • Object String/Number/Symbol,將 Object 轉換成 Primitive Value
  • 不然,返回 false
// '12' ==> 12;
// 返回 true
12 == '12'

// 轉 boolean: [] == 0
// 轉 object: '' == 0
// 轉 string: 0 == 0
// 返回 true
[] == false

// 轉 object: '45' == 45
// 轉 string: 45 == 45
// 返回 true
[45] == 45

// 單目: {} == false
// 轉 boolean: {} == 0
// 轉 object: '[object Object]' == 0
// 轉 string: NaN == 0
// 返回 false
{} == !{}

// 單目:[] == fasle
// 轉 boolean: [] == 0
// 轉 array: "" == 0
// 轉 string: 0 == 0
// 返回 true
[] == ![]

[] == []
[] == 0

嚴格比較 (===)

  • 類型不一樣,直接返回 false
  • Number 類型判斷:有 NaN 就 false;
  • 特別的 +0 === -0;
  • 最後調用 SameValueNonNumber
另外 != 和 !== 則是指出了 A != B 與 !(A == B) 是徹底等價的。在判斷 !=/!== 時,其實就是在判斷 ==/===.

不等關係

  • 兩邊操做數調用 ToPrimitive 轉換爲 Primitive Value
  • 因爲 Primitive Value 出來有 StringNumber 兩種結果,分別有不一樣的比較規則;

    1. 若是兩邊的值都是 String,則 按 code unit 比較,
    2. 若是一邊是 Number,則將另外一邊也轉換爲 Number;注意 Number 須要處理 +0/-0/NaN/Infinity 等狀況
// 注意轉換後爲 '45' < '46'
// 按字符串規則比較 最終比較的是 '5'.charCodeAt() < '6'.charCodeAt() => 53 < 54
// 返回 true
[45] < [46]

// 同理 [10] < [9] 最後進行的是 '10' < '9' 的比較,是字符串之間的筆記,不會轉換爲數字間的比較,
// 其實最終比較的是 '1'.charCodeAt() < '9'.charCodeAt() => 49 < 57.
[10] < [9]

練習題

// 每一個表達式是 true 仍是 false 呢?爲啥呢?

// 初階
!{}
12 == '12'
'false' == false
null == undefined

// 高階
[] == []
[] == false
[] === false
[45] == 45

// 終階
[45] < [46] ?
[10] < [9] ?
{} == !{}
{} != {}
-0 === +0
NaN === NaN
NaN != NaN

// 轉換條件 轉換後類型 結果
[]+[] // String 「」
[1,2]+[3,4] // String 「1,23,4」
[]+{} // String 「[object Object]」
[1,2] + {a:1} // String 「1,2[object Object]」
{}+[] // Number 0
{}+[1] //Number 1
{a:1}+[1,2] // Number NaN
{a:1}+{b:2} // Chrome - String 「[object Object][object Object]」 (背後實現eval)
{a:1}+{b:2} // Firefox - Number NaN
true+true // Number 2
1+{a:1} // String 「1[object Object]」

reference

JavaScript 中的隱式類型轉換的規範

JavaScript 運算符規則與隱式類型轉換詳解

JavaScript類型:關於類型,有哪些你不知道的細節?

深刻淺出弱類型JS的隱式轉換

JavaScript字符串間的比較

ecma-sec-relational-operators

相關文章
相關標籤/搜索