【學習筆記】JS類型轉換整理

我們寫JavaScript肯定會涉及到各種類型轉換,有些類型轉換簡單易懂,但有些轉換卻會意想不到,甚至帶來很多的麻煩。
所以我這篇學習筆記旨在梳理一下這種轉換,加強一下自己的理解,也方便大家查閱一些問題,如文章中有不妥之處請幫忙指正
下面開始正文:

1.類型

1.1 內置類型

JS有七種類型:
1.空值(null)
2.未定義(undefined)
3.字符串(string)
4.數字(number)
5.布爾(boolean)
6.對象(object)
7.符號(symblo,ES6新增)
除對象(object)外,其他都是基本類型

1.2 類型判斷

使用 typeof 來查看對應值的類型

typeof undefined //undefined
typeof true //boolean
typeof 12 //number
typeof "12" //string
typeof {num:12} //object
typeof Symbol() //symbol

以上六種類型均符合我們預期

typeof null //object

但是null卻有些特殊,它的返回結果並不是如我們所想。
null是唯一 一個用typeof檢測會返回"object"的基本類型值。

1.3 undefined 和 undeclared

有時候開發時會經常犯一些理解性錯誤,將undefined和undeclared等同起來,但其實是完全兩回事。

var a
console.log(a) //undefined
console.log(b) //ReferenceError: b is not defined
console.log(typeof a) //undefined
console.log(typeof b) //undefined

已在作用域中聲明但是沒有賦值的變量是undefined,相反沒有在作用域中聲明的變量是undeclared.
但是如例子中,雖然兩個變量情況不同,但是typeof對於undefined和undeclared的處理方式都是相同的,全爲undefined,所以看着真的好像啊emmm~~~

雖然b是一個Undeclared變量,但是typeof b不會報錯,這是因爲typeof有一個特殊的安全防範機制

1.4 undefined,null和{}

開發過程中,發現經常出現這三種情況,現在從不同方面進行比較

console.log(typeof undefined) //undefined 
console.log(typeof null) //object
console.log(typeof {})   //object

console.log({} === null) //false
console.log(Boolean({})) //true
console.log(Boolean(null)) //false

console.log(Number({})) //NaN
console.log(Number(null)) //0
console.log(Number(undefined)) //NaN

如上面所說,從類型能看出,undefined的類型是undefined,但是null和{}都是object。
另外,null和{}是不相同的,null值表示一個空對象指針,如果打算定義一個變量準備在將來用於保存對象,可以將變量初始化爲null。 {}其實是一個對象,經歷過聲明和初始化,只不過裏面沒有存儲數據,是一個空對象。
進行布爾值轉換時,{}是爲true的,而null是爲false,在開發中有使用到這兩個時候,還是要注意的。(我是踩過這個坑的~~~,挺疼的)

2.強制類型轉換

將值從一種類型轉換到另一種類型通常稱爲強制類型轉換,而將轉換髮生的階段不同,暫且將它們命名爲“隱式強制類型轉換”和“顯式強制類型轉換

const a = 11
const b = a + '' //隱式強制類型轉換
const c = String(a) //顯示強制類型轉換

對變量b來說,進行的是隱式轉換,由於 +運算符的其中一個操作數是字符串,所以是字符串拼接操作,將數字11隱式強制換行爲字符串“11”
對應變量c,使用String的方法則顯式強制轉換爲字符串

2.1 顯式強制轉換

2.1.1 字符串和數字之間轉換

字符串和數字之間的轉換通過String()和Number()這兩個方法來進行

const a = 11
const b = String(a) // "11"

const c = "111"
const d = Number(c) // 111

2.1.2 顯示解析數字字符串

解析字符串中的數字和將字符串強制類型轉換爲數字的返回結果都是數字,但是解析和轉換是有區別的

const a = "42"
const b = "42ha1"

console.log(Number(a)) //42
console.log(parseInt(a)) //42

console.log(Number(b)) //NaN
console.log(parseInt(b)) //42

解析允許字符串中含有非數字字符,解析會從左到右的順序,遇到非數字字符停止。
轉換不允許出現非數字字符,否則會失敗並返回NaN

備註:parseInt是針對字符串的,轉其他類型不可以

2.1.3 顯示轉換爲布爾值

使用Boolean()將非布爾值強制轉換爲布爾值,但這個不常用

const a = 0
const b = 1
console.log(Boolean(a)) //false
console.log(Boolean(b)) //true

常用的方法爲!!

const a = 0
const b = 1
console.log(!!a) //false
console.log(!!b) //true

另外,我們在開發中經常會這麼寫:

const instance = {}
if(this.instance) {/*進行的操作*/}

像在if()這樣的上下文中,如果沒有使用Boolean()和!!進行顯示強制轉換,便會自動隱式進行ToBoolean的轉換。
如果這時你想判斷的是當instance有數據時進行某些操作,使用這種寫法就不會達成你的需求,因爲Boolean({})是爲true的,採用這樣寫法永遠都會執行裏面的操作,要小心

2.2 隱式強制轉換

採用隱式強制轉換會讓代碼更加簡潔,減少冗餘 ,但是問題也不少,所以需要好好了解這種轉換。(吐槽一句:隱式轉換真的好懵圈,一定要耐心研究,坑挺多的~~)

2.2.1 字符串和數字之間的隱式強制類型轉換

JS中常會用到+運算符進行一些操作,包括數字運算和字符串拼接,如圖:

let a = "12"
let b = "3"
let c = 12
let d = 3
console.log(a+b) //"123"
console.log(b+c) // "312"
console.log(c+d) // 15

對上面例子普遍理解就是,因爲“12”和“3”都是字符串,所以進行+執行時候,只要某一個或兩個操作數是字符串,就進行字符串拼接操作。這個理解沒有錯,但不全,實際情況更加複雜。
接下來看一個例子:

let e = [1,2]
let f = [3,4]
console.log(e+f) //"1,23,4"

圖中是兩個數組,沒有字符串,但是進行+執行時,他們都被進行強制轉換爲字符串,然後進行拼接操作。
原因如下:
根據ES5規範11.6.1節:如果某個操作時字符串或者能夠通過以下步驟轉換爲字符串,+將進行拼接操作。
(本人吐槽:規範太難理解,知道怎麼用就好了吧~~)

2.2.2 隱式強制轉換爲布爾值

布爾值的隱式轉換時最爲常見的,也是最容易出問題的
常見幾種類型:
1.if(…)語句中的條件判斷;
2.for(…;…;…)語句中第二個的條件判斷
3.while(…)語句中的條件判斷
4. ?:中的條件判斷

2.2.3 ||和&&

邏輯運算符也是我們經常使用的,但很多人都認爲使用邏輯運算符返回的結果是布爾值,但其實並不是它們的返回值是兩個操作數其中一個的值
詳見幾個例子:

let a = 12
let b = "abc"
let c = null

console.log(a && b) // "abc"
console.log(a || b) // 12
console.log(a && c) // null
console.log(a || c) // 12
console.log(c && b) // null
console.log(c || b) // "abc"

(a && b)(a || b)爲例進行說明:
|| 和 &&首先會對第一個操作數(a)進行條件判斷,如果不是布爾值,就先進行布爾強制轉換,然後再執行條件判斷。
&&:如果第一個操作數條件判斷結果爲true,就返回第二個操作數(b)的值,如果結果爲false,就返回第一個操作數(a)
|| :它和&&正好相反,如果第一個操作數條件判斷結果爲true,就返回第一個操作數(a)的值,如果結果爲false,則返回第二個操作數(b)
另外,由於&&這種特性,在開發時候就可以用前面的表達式爲後面的表達式“把關”,例如

price.totalPrice && price.totalPrice.toFixed(2)

在 這個代碼中,首先檢驗price下面的totalPrice是否存在,如果存在進行後面toFixed的操作,如果totalPrice不存在,就不進行後續操作了,防止toFixed的報錯。
使用這種寫法就更加簡潔,就不用if(price.totalPrice) {…}這種判斷寫法了。

最後在看一個例子:

let a = 42
let b = "abc"
let c = null
if (a && (b || c)) {
  console.log('hi')
}

通過本節會知道,a && (b || c)的結果是“abc”,而非true,但是在2.2.2節中說到,if(…)語句中的條件判斷會進行隱式強制轉換爲布爾值,也就是將“abc”強制轉換,所以結果值爲true。通過這些隱式強制轉換,使得條件判斷沒有發生過問題。

2.2.4 寬鬆相等和嚴格相等

寬鬆相等== 和 嚴格相等=== 有什麼區別是面試經常提問題,很多面經裏面會說 “==是檢查值是否相等,===是檢查值和類型是否相等”,但其實並不準確。
正確解釋: ==允許在相等比較中進行強制轉換,但是 ===不允許

2.2.4.1 其他類型和布爾類型之間的相等比較

來一個好玩的例子

let a = "42"
let b = true
console.log(a == b) // false
console.log(a == c) // false

會不會有疑問啊?“42”明明就是真值,爲什麼和true不相等呢?
在規範11.9.3.4-7提及:
(1)If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
(2)If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
(3)Type(x) is String and Type(y) is Number,
return the result of the comparison ToNumber(x) == y.

所以再看剛纔例子:
Type(true)是Boolean,進行ToNumber轉換爲1,變成“42”==1,二者類型不同 ,繼續轉換,Type(“42”)爲String,轉換爲42,所以最後對比的是 42 == 1,結果爲false。

(是不是很懵啊~~反正我是暈了,爲了自己心裏健康,建議這種就是玩玩就好,真正開發還是別寫了,別和 true和 false進行判斷!!)

使用if(a){…}的寫法不香麼?

或者if(!!a){…}也不錯啊

2.2.4.2 安全使用隱式強制轉換

在使用==時候,需要對兩邊的值進行推敲:
1.當兩邊的值有true和false,千萬不要使用 ==
2.當兩邊的值有[],"",和0,最好不要使用 ==
至於其他情況,按照自己需求使用。
(個人觀點:有時候開發時候使用 ==編輯器都會報提醒建議使用 ===,很多人也會說直接使用 ===,其實到底使用哪種相等完全取決於自己需求使用,在瞭解轉換的規則之後,寬鬆相等也會帶來簡單的開發吧)

2.3 好玩的例子(一定要看)

console.log(String({})) //“[object Object]”
console.log(Number(undefined))//NaN
console.log(Number([]))//0

console.log({} + []) //“[object Object]”
console.log([] + {}) //“[object Object]”

console.log({} + 0) //“[object Object]0”
console.log('0' + undefined) //“0undefined”
console.log(0 + undefined) //NaN

最後玩幾個小例子,第4,5,6,7個按照上面講的,將他們分別進行String隱式強制轉換,然後以字符串形式拼接。而8是進行了Number的隱式強制轉換。

再看一個在控制檯的輸出:
在這裏插入圖片描述
但是底下這個結果爲什麼就和上面的例子不一樣了,不是“[object object]”?

這是因爲在第一行代碼中,{}是被當作一個獨立的空代碼塊(不進行任何操作),最後+[],將[]顯示強制轉換爲0。

但是在第二行代碼中,{}出現在+運算表達式中,被作爲一個值(空對象)來處理,所以它的處理方式和上面例子相同,將[]和{}都轉爲字符串。

(各種神奇例子很多,大家發現好玩的,可以一併留言哦~)

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