Js之類型轉換

最近在看冴羽的博客,發現東西太多,也難記。所以還是決定照着過一遍,加深印象,也便於以後查閱。
原文請看:冴羽的博客
接下來進入正題,先是基本類型之間的轉換:

js數據類型可以分爲兩類:
可變的引用類型: object(array ,function,正則);
不可變的原始類型: null, undefined, number, string, boolean, symbol(es6)

一、原始類型的轉換

1.1 原始值轉布爾

轉換成布爾類型,在 JavaScript 中,只有 6 種值可以被轉換成 false,其他都會被轉換成 true。

console.log(Boolean()) // false
console.log(Boolean(false)) // false
console.log(Boolean(undefined)) // false
console.log(Boolean(null)) // false
console.log(Boolean(+0)) // false
console.log(Boolean(-0)) // false
console.log(Boolean(NaN)) // false
console.log(Boolean("")) // false

1.2 原始值轉數字

Number()
我們可以使用 Number 函數將類型轉換成數字類型,如果參數無法被轉換爲數字,則返回 NaN。
在這裏插入圖片描述
根據規範(上圖),如果 Number 函數不傳參數,返回 +0,如果有參數,調用 ToNumber(value)
注意這個 ToNumber 表示的是一個底層規範實現上的方法,並沒有直接暴露出來。

ToNumber 則直接給了一個對應的結果表。表如下:
在這裏插入圖片描述

console.log(Number()) // +0

console.log(Number(undefined)) // NaN
console.log(Number(null)) // +0

console.log(Number(false)) // +0
console.log(Number(true)) // 1

console.log(Number("123")) // 123
console.log(Number("-123")) // -123
console.log(Number("1.2")) // 1.2
console.log(Number("000123")) // 123
console.log(Number("-000123")) // -123

console.log(Number("0x11")) // 17

console.log(Number("")) // 0
console.log(Number(" ")) // 0

console.log(Number("123 123")) // NaN
console.log(Number("foo")) // NaN
console.log(Number("100a")) // NaN

Number傳入一個字符串,如果有一個字符不是數字,結果就會返回NaN;我們還會使用更加靈活的parseInt和parseFloat。
parseInt只解析整數,parseFloat可以解析整數和浮點數;
parseInt 和 parseFloat 都會跳過任意數量的前導空格,儘可能解析更多數值字符,並忽略後面的內容。如果第一個非空格字符是非法的數字直接量,將最終返回 NaN:

console.log(parseInt("3 abc")) // 3
console.log(parseFloat("3.14 abc")) // 3.14
console.log(parseInt("-12.34")) // -12
console.log(parseInt("0xFF")) // 255
console.log(parseFloat(".1")) // 0.1
console.log(parseInt("0.1")) // 0

1.3 原始值轉字符

我們使用 String 函數將類型轉換成字符串類型,依然先看 規範15.5.1.1中有關 String 函數的介紹:
在這裏插入圖片描述
如果 String 函數不傳參數,返回空字符串,如果有參數,調用 ToString(value),而 ToString 也給了一個對應的結果表。表如下:
在這裏插入圖片描述

console.log(String()) // 空字符串

console.log(String(undefined)) // undefined
console.log(String(null)) // null

console.log(String(false)) // false
console.log(String(true)) // true

console.log(String(0)) // 0
console.log(String(-0)) // 0
console.log(String(NaN)) // NaN
console.log(String(Infinity)) // Infinity
console.log(String(-Infinity)) // -Infinity
console.log(String(1)) // 1

注意這裏的 ToString 和上一節的 ToNumber 都是底層規範實現的方法,並沒有直接暴露出來。

1.4 原始值轉對象

原始值到對象的轉換非常簡單,原始值通過調用 String()、Number() 或者 Boolean() 構造函數,轉換爲它們各自的包裝對象。
null 和 undefined 屬於例外,當將它們用在期望是一個對象的地方都會造成一個類型錯誤 (TypeError) 異常,而不會執行正常的轉換。

var a = 1;
console.log(typeof a); // number
var b = new Number(a);
console.log(typeof b); // object

二、引用類型的轉換

2.1 對象轉布爾值

對象到布爾值的轉換非常簡單:所有對象(包括數組和函數)都轉換爲 true。對於包裝對象也是這樣,舉個例子:

console.log(Boolean(new Boolean(false))) // true

2.2.1對象轉字符串和數字

對象到字符串和對象到數字的轉換都是通過調用待轉換對象的一個方法來完成的。而 JavaScript 對象有兩個不同的方法來執行轉換,一個是 toString,一個是 valueOf。注意這個跟上面所說的 ToString 和 ToNumber 是不同的,這兩個方法是真實暴露出來的方法。

toString():
所有的對象除了 null 和 undefined 之外的任何值都具有 toString 方法;
通常情況下,它和使用 String 方法返回的結果一致。toString 方法的作用在於返回一個反映這個對象的字符串,然而這纔是情況複雜的開始。

Object.prototype.toString.call({a: 1}) // "[object Object]"
({a: 1}).toString() // "[object Object]"
({a: 1}).toString === Object.prototype.toString // true

我們可以看出當調用對象的 toString 方法時,其實調用的是 Object.prototype 上的 toString 方法。

然而 JavaScript 下的很多類根據各自的特點,定義了更多版本的 toString 方法。例如:

  1. 數組的 toString 方法將每個數組元素轉換成一個字符串,並在元素之間添加逗號後合併成結果字符串。
  2. 函數的 toString 方法返回源代碼字符串。
  3. 日期的 toString 方法返回一個可讀的日期和時間字符串。
  4. RegExp 的 toString 方法返回一個表示正則表達式直接量的字符串。
console.log(({}).toString()) // [object Object]

console.log([].toString()) // ""
console.log([0].toString()) // 0
console.log([1, 2, 3].toString()) // 1,2,3
console.log((function(){var a = 1;}).toString()) // function (){var a = 1;}
console.log((/\d+/g).toString()) // /\d+/g
console.log((new Date(2010, 0, 1)).toString()) // Fri Jan 01 2010 00:00:00 GMT+0800 (CST)

valueOf():
而另一個轉換對象的函數是 valueOf,表示對象的原始值。
默認的 valueOf 方法返回這個對象本身,數組、函數、正則簡單的繼承了這個默認方法,也會返回對象本身。
日期是一個例外,它會返回它的一個內容表示: 1970 年 1 月 1 日以來的毫秒數。

var arr = [1,2,3]
console.log(arr.valueOf()) //[1, 2, 3]
var date = new Date(2017, 4, 21);
console.log(date.valueOf()) // 1495296000000

2.2.2對象接着轉字符串和數字

瞭解了 toString 方法和 valueOf 方法,我們分析下從對象到字符串是如何轉換的。看規範 ES5 9.8,其實就是 ToString (value)方法的對應表,只是這次我們加上 Object 的轉換規則:
在這裏插入圖片描述
在這裏插入圖片描述在這裏插入圖片描述
所謂的 ToPrimitive 方法,其實就是輸入一個值,然後返回一個一定是基本類型的值。我們總結一下,當我們用 String 方法轉化一個值的時候:

  1. 如果是基本類型,就參照 “原始值轉字符” 這一節的對應表;
  2. 如果不是基本類型,我們會將調用一個 ToPrimitive 方法,將其(對象)轉爲基本類型,然後再參照“原始值轉字符” 這一節的對應表進行轉換。

雖然轉換成基本值都會使用 ToPrimitive 方法,但傳參有不同,最後的處理也有不同,轉字符串調用的是 ToString,轉數字調用 ToNumber。

接下來讓我看一下,ToPrimitive()是如何將對象轉化爲基本值類型的!

2.2.3 ToPrimitive

讓我們看規範 9.1,函數語法表示如下:

//input 表示要處理的輸入值
//PrefefrredType, 非必填,表示希望轉換成的類型,有兩個值可以選擇, Number和String.
ToPrimitive(input[, PreferredType])

1.當不傳入 PreferredType 指定裝換類型時:
如果 input 是日期類型,相當於傳入 String,否則,都相當於傳入 Number;如果傳入的 input 是 Undefined、Null、Boolean、Number、String 基本類型,直接返回該值。

2.ToPrimitive(obj, Number)時:

1.如果 obj 爲 基本類型,直接返回
2.否則,調用 valueOf 方法,如果返回一個原始值,則 JavaScript 將其返回。
3.否則,調用 toString 方法,如果返回一個原始值,則 JavaScript 將其返回。
4.否則,JavaScript 拋出一個類型錯誤異常。

3.ToPrimitive(obj, String)時:
1.如果 obj爲 基本類型,直接返回
2.否則,調用 toString 方法,如果返回一個原始值,則 JavaScript 將其返回。
3.否則,調用 valueOf 方法,如果返回一個原始值,則 JavaScript 將其返回。
4.否則,JavaScript 拋出一個類型錯誤異常。

2.2.4 對象轉字符串

所以總結下,對象轉字符串可以概括爲:

如果對象具有 toString 方法,則調用這個方法。如果他返回一個原始值,JavaScript 將這個值轉換爲字符串,並返回這個字符串結果。
如果對象沒有 toString 方法,或者這個方法並不返回一個原始值,那麼 JavaScript 會調用 valueOf 方法。如果存在這個方法,則 JavaScript 調用它。如果返回值是原始值,JavaScript 將這個值轉換爲字符串,並返回這個字符串的結果。
否則,JavaScript 無法從 toString 或者 valueOf 獲得一個原始值,這時它將拋出一個類型錯誤異常。

2.2.5 對象轉數字

對象轉數字的過程中,JavaScript 做了同樣的事情,只是它會首先嚐試 valueOf 方法

如果對象具有 valueOf 方法,且返回一個原始值,則 JavaScript 將這個原始值轉換爲數字並返回這個數字
否則,如果對象具有 toString 方法,且返回一個原始值,則 JavaScript 將其轉換並返回。
否則,JavaScript 拋出一個類型錯誤異常。

console.log(Number({})) // NaN
console.log(Number({a : 1})) // NaN

console.log(Number([])) // 0
console.log(Number([0])) // 0
console.log(Number([1, 2, 3])) // NaN
console.log(Number(function(){var a = 1;})) // NaN
console.log(Number(/\d+/g)) // NaN
console.log(Number(new Date(2010, 0, 1))) // 1262275200000
console.log(Number(new Error('a'))) // NaN

注意,在這個例子中,[] 和 [0] 都返回了 0,而 [1, 2, 3] 卻返回了一個 NaN。我們分析一下原因:

當我們 Number([]) 的時候,先調用 [] 的 valueOf 方法,此時返回 [],因爲返回了一個對象而不是原始值,所以又調用了 toString 方法,此時返回一個空字符串,接下來調用 ToNumber 這個規範上的方法,參照對應表,轉換爲 0, 所以最後的結果爲 0。

而當我們 Number([1, 2, 3]) 的時候,先調用 [1, 2, 3] 的 valueOf 方法,此時返回 [1, 2, 3],再調用 toString 方法,此時返回 1,2,3,接下來調用 ToNumber,參照對應表,因爲無法轉換爲數字,所以最後的結果爲 NaN。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章