摘要:隱式類型轉(zhuǎn)換通常在邏輯判斷或者有邏輯運(yùn)算符時(shí)被觸發(fā)。一元加號(hào)執(zhí)行字符串的類型轉(zhuǎn)換。邏輯運(yùn)算符和將值轉(zhuǎn)為型,但是會(huì)返回原始值不是。計(jì)算從表達(dá)式開始,該表達(dá)式通過方法轉(zhuǎn)換為空字符串,然后轉(zhuǎn)換為??偨Y(jié)查看原文關(guān)注每日一道面試題詳解
類型轉(zhuǎn)換是將值從一種類型轉(zhuǎn)換為另一種類型的過程(比如字符串轉(zhuǎn)數(shù)字,對(duì)象轉(zhuǎn)布爾值等)。任何類型不論是原始類型還是對(duì)象類型都可以進(jìn)行類型轉(zhuǎn)換,JavaScript 的原始類型有:number, string, boolean, null, undefined, Symbol。
本文將通過 17 道題目來深入的了解 JS 中的類型轉(zhuǎn)換,通過閱讀本文之后,你將能自信的回答出下面題目的答案,并且能夠理解背后的原理。在文章的最后,我講寫出答案并解釋。在看答案之前,你可以把答案寫下來,最后再對(duì)照一下,便于找出理解有誤的地方。
true + false 12 / "6" "number" + 15 + 3 15 + 3 + "number" [1] > null "foo" + + "bar" "true" == true false == "false" null == "" !!"false" == !!"true" ["x"] == "x" [] + null + 1 [1,2,3] == [1,2,3] {} + [] + {} + [1] ! + [] + [] + ![] new Date(0) - 0 new Date(0) + 0
類似于上面的這些問題大概率也會(huì)在 JS 面試中被問到, 所以繼續(xù)往下讀。
隱式 vs 顯式類型轉(zhuǎn)換類型轉(zhuǎn)換可以分為隱式類型轉(zhuǎn)換和顯式類型轉(zhuǎn)換。
當(dāng)開發(fā)人員通過編寫適當(dāng)?shù)拇a(如Number(value))用于在類型之間進(jìn)行轉(zhuǎn)換時(shí),就稱為顯式類型強(qiáng)制轉(zhuǎn)換(或強(qiáng)制類型轉(zhuǎn)換)。
然而 JavaScript 是弱類型語言,在某些操作下,值可以在兩種類型之間自動(dòng)的轉(zhuǎn)換,這叫做隱式類型轉(zhuǎn)換。在對(duì)不同類型的值使用運(yùn)算符時(shí)通常會(huì)發(fā)生隱式類型轉(zhuǎn)換。比如 1 == null, 2 / "5", null + new Date()。當(dāng)值被 if 語句包裹時(shí)也有可能發(fā)生,比如 if(value) {} 會(huì)將 value 轉(zhuǎn)換為 boolean類型。
嚴(yán)格相等運(yùn)算符(===)不會(huì)觸發(fā)類型隱式轉(zhuǎn)換,所以它可以用來比較值和類型是否都相等。
隱式類型轉(zhuǎn)換是一把雙刃劍,使用它雖然可以寫更少的代碼但有時(shí)候會(huì)出現(xiàn)難以被發(fā)現(xiàn)的bug。
三種類型轉(zhuǎn)換我們需要知道的第一個(gè)規(guī)則是:在 JS 中只有 3 種類型的轉(zhuǎn)換
to string
to boolean
to number
第二,類型轉(zhuǎn)換的邏輯在原始類型和對(duì)象類型上是不同的,但是他們都只會(huì)轉(zhuǎn)換成上面 3 種類型之一。
我們首先分析一下原始類型轉(zhuǎn)換。
String 類型轉(zhuǎn)換String() 方法可以用來顯式將值轉(zhuǎn)為字符串,隱式轉(zhuǎn)換通常在有 + 運(yùn)算符并且有一個(gè)操作數(shù)是 string 類型時(shí)被觸發(fā),如:
String(123) // 顯式類型轉(zhuǎn)換 123 + "" // 隱式類型轉(zhuǎn)換
所有原始類型轉(zhuǎn) String 類型
String(123) // "123" String(-12.3) // "-12.3" String(null) // "null" String(undefined) // "undefined" String(true) // "true"
Symbol 類型轉(zhuǎn) String 類型是比較嚴(yán)格的,它只能被顯式的轉(zhuǎn)換
String(Symbol("symbol")) // "Symbol(symbol)" "" + Symbol("symbol") // TypeError is thrownBoolean 類型轉(zhuǎn)換
Boolean() 方法可以用來顯式將值轉(zhuǎn)換成 boolean 型。
隱式類型轉(zhuǎn)換通常在邏輯判斷或者有邏輯運(yùn)算符時(shí)被觸發(fā)(|| && !)。
Boolean(2) // 顯示類型轉(zhuǎn)換 if(2) {} // 邏輯判斷觸發(fā)隱式類型轉(zhuǎn)換 !!2 // 邏輯運(yùn)算符觸發(fā)隱式類型轉(zhuǎn)換 2 || "hello" // 邏輯運(yùn)算符觸發(fā)隱式類型轉(zhuǎn)換
注意: 邏輯運(yùn)算符(比如 || 和 &&)是在內(nèi)部做了 boolean 類型轉(zhuǎn)換,但實(shí)際上返回的是原始操作數(shù)的值,即使他們都不是 boolean 類型。
// 返回 number 類型 123,而不是 boolean 型 true // "hello" 和 "123" 仍然在內(nèi)部會(huì)轉(zhuǎn)換成 boolean 型來計(jì)算表達(dá)式 let x = "hello" && 123 // x === 123
boolean 類型轉(zhuǎn)換只會(huì)有 true 或者 false 兩種結(jié)果。
Boolean("") // false Boolean(0) // false Boolean(-0) // false Boolean(NaN) // false Boolean(null) // false Boolean(undefined) // false Boolean(false) // false
任何不在上面列表中的值都會(huì)轉(zhuǎn)換為 true, 包括 object, function, Array, Date 等,Symbol 類型是真值,空對(duì)象和空數(shù)組也是真值。
Boolean({}) // true Boolean([]) // true Boolean(Symbol()) // true !!Symbol() // true Boolean(function() {}) // trueNumber 類型轉(zhuǎn)換
和 Boolean()、String() 方法一樣, Number() 方法可以用來顯式將值轉(zhuǎn)換成 number 類型。
number 的隱式類型轉(zhuǎn)換是比較復(fù)雜的,因?yàn)樗梢栽谙旅娑喾N情況下被觸發(fā)。
比較操作(>, <, <=, >=)
按位操作(| & ^ ~)
算數(shù)操作(- + * / %), 注意,當(dāng) + 操作存在任意的操作數(shù)是 string 類型時(shí),不會(huì)觸發(fā) number 類型的隱式轉(zhuǎn)換
一 元 + 操作
非嚴(yán)格相等操作(== 或者 !== ),注意,== 操作兩個(gè)操作數(shù)都是 string 類型時(shí),不會(huì)發(fā)生 number 類型的隱式轉(zhuǎn)換
Number("123") // 顯示類型轉(zhuǎn)換 + "123" // 隱式類型轉(zhuǎn)換 123 != "456" // 隱式類型轉(zhuǎn)換 4 > "5" // 隱式類型轉(zhuǎn)換 5 / null // 隱式類型轉(zhuǎn)換 true | 0 // 隱式類型轉(zhuǎn)換
接下來看一下原始類型顯示轉(zhuǎn)換 number 類型會(huì)發(fā)生什么
Number(null) // 0 Number(undefined) // NaN Number(true) // 1 Number(false) // 0 Number(" 12 ") // 12 Number("-12.34") // -12.34 Number(" ") // 0 Number(" 12s ") // NaN Number(123) // 123
當(dāng)將一個(gè)字符串轉(zhuǎn)換為一個(gè)數(shù)字時(shí),引擎首先刪除前尾空格、n、t 字符,如果被修剪的字符串不成為一個(gè)有效的數(shù)字,則返回 NaN。如果字符串為空,則返回 0。
Number() 方法對(duì)于 null 和 undefined 的處理是不同的, null 會(huì)轉(zhuǎn)換為 0, undefined 會(huì)轉(zhuǎn)換為 NaN
不管是顯式還是隱式轉(zhuǎn)換都不能將 Symbol 類型轉(zhuǎn)為 number 類型,當(dāng)試圖這樣操作時(shí),會(huì)拋出錯(cuò)誤。
Number(Symbol("my symbol")) // TypeError is thrown +Symbol("123") // TypeError is thrown
這里有 2 個(gè)特殊的規(guī)則需要記住:
當(dāng)將 == 應(yīng)用于 null 或 undefined 時(shí),不會(huì)發(fā)生數(shù)值轉(zhuǎn)換。null 只等于 null 或 undefined,不等于其他任何值。
null == 0 // false, null is not converted to 0 null == null // true undefined == undefined // true null == undefined // true undefined == 0 // false
NaN 不等于任何值,包括它自己
NaN === NaN // false if(value !== value) { console.log("the value is NaN") }object 類型轉(zhuǎn)換
到這里我們已經(jīng)深入了解了原始類型的轉(zhuǎn)換,接下來我們來看一下 object 類型的轉(zhuǎn)換。
當(dāng)涉及到對(duì)象的操作比如:[1] + [2,3],引擎首先會(huì)嘗試將 object 類型轉(zhuǎn)為原始類型,然后在將原始類型轉(zhuǎn)為最終需要的類型,而且仍然只有 3 種類型的轉(zhuǎn)換:number, string, boolean
最簡單的情況是 boolean 類型的轉(zhuǎn)換,任何非原始類型總是會(huì)轉(zhuǎn)換成 true,無論對(duì)象或數(shù)組是否為空。
對(duì)象通過內(nèi)部 [[ToPrimitive]] 方法轉(zhuǎn)換為原始類型,該方法負(fù)責(zé)數(shù)字和字符串轉(zhuǎn)換。
[[ToPrimitive]] 方法接受兩個(gè)參數(shù)一個(gè)輸入值和一個(gè)需要轉(zhuǎn)換的類型(Numer or String)
number 和 string的轉(zhuǎn)換都使用了對(duì)象的兩個(gè)方法: valueOf 和 toString。這兩個(gè)方法都在 Object.prototype 上被聲明,因此可用于任何派生類,比如 Date, Array等。
通常上 [[ToPrimitive]] 算法如下:
如果輸入的值已經(jīng)是原始類型,直接返回這個(gè)值。
輸入的值調(diào)用 toString() 方法,如果結(jié)果是原始類型,則返回。
輸入的值調(diào)用 valueOf() 方法,如果結(jié)果是原始類型,則返回。
如果上面 3 個(gè)步驟之后,轉(zhuǎn)換后的值仍然不是原始類型,則拋出 TypeError 錯(cuò)誤。
number 類型的轉(zhuǎn)換首先會(huì)調(diào)用 valueOf() 方法,如果不是原始值在調(diào)用 toString() 方法。 string 類型的轉(zhuǎn)換則相反。
大多數(shù) JS 內(nèi)置對(duì)象類型的 valueOf() 返回這個(gè)對(duì)象本身,其結(jié)果經(jīng)常被忽略,因?yàn)樗皇且粋€(gè)原始類型。所以大多數(shù)情況下當(dāng) object 需要轉(zhuǎn)換成 number 或 string 類型時(shí)最終都調(diào)用了 toString() 方法。
當(dāng)運(yùn)算符不同時(shí),[[ToPrimitive]] 方法接受的轉(zhuǎn)換類型參數(shù)也不相同。當(dāng)存在 == 或者 + 運(yùn)算符時(shí)一般會(huì)先觸發(fā) number 類型的轉(zhuǎn)換再觸發(fā) string 類型轉(zhuǎn)換。
在 JS 中你可以通過重寫對(duì)象的 toString 和 valueOf 方法來修改對(duì)象到原始類型轉(zhuǎn)換的邏輯。
答案解析接下來我們按照之前的轉(zhuǎn)換邏輯來解釋一下每一道題,看一下是否和你的答案一樣。
true + false // 1
"+" 運(yùn)算符會(huì)觸發(fā) number 類型轉(zhuǎn)換對(duì)于 true 和 false
12 / "6" // 2
算數(shù)運(yùn)算符會(huì)把字符串 ‘6’ 轉(zhuǎn)為 number 類型
"number" + 15 + 3 // "number153"
"+" 運(yùn)算符按從左到右的順序的執(zhí)行,所以優(yōu)先執(zhí)行 “number” + 15, 把 15 轉(zhuǎn)為 string 類型,得到 “number15” 然后同理執(zhí)行 “number15” + 3
15 + 3 + "number" // "18number"
15 + 3 先執(zhí)行,運(yùn)算符兩邊都是 number 類型 ,不用轉(zhuǎn)換,然后執(zhí)行 18 + “number” 最終得到 “18number”
[1] > null // true ==> "1" > 0 ==> 1 > 0 ==> true
比較運(yùn)算符 > 執(zhí)行 number 類型隱式轉(zhuǎn)換。
"foo" + + "bar" // "fooNaN" ==> "foo" + (+"bar") ==> "foo" + NaN ==> "fooNaN"
一元 + 運(yùn)算符比二元 + 運(yùn)算符具有更高的優(yōu)先級(jí)。所以 + bar表達(dá)式先求值。一元加號(hào)執(zhí)行字符串“bar” 的 number 類型轉(zhuǎn)換。因?yàn)樽址淮硪粋€(gè)有效的數(shù)字,所以結(jié)果是NaN。在第二步中,計(jì)算表達(dá)式"foo" + NaN。
"true" == true // false ==> NaN == 1 ==> false "false" == false // false ==> NaN == 0 ==> false
== 運(yùn)算符執(zhí)行 number 類型轉(zhuǎn)換,"true" 轉(zhuǎn)換為 NaN, boolean 類型 true 轉(zhuǎn)換為 1
null == "" // false
null 不等于任何值除了 null 和 undefined
!!"false" == !!"true" // true ==> true == true ==> true
!! 運(yùn)算符將字符串 "true" 和 "false" 轉(zhuǎn)為 boolean 類型 true, 因?yàn)椴皇强兆址缓髢蛇叾际?boolean 型不在執(zhí)行隱式轉(zhuǎn)換操作。
["x"] == "x" // true
== 運(yùn)算符對(duì)數(shù)組類型執(zhí)行 number 轉(zhuǎn)換,先調(diào)用對(duì)象的 valueOf() 方法,結(jié)果是數(shù)組本身,不是原始類型值,所以執(zhí)行對(duì)象的 toString() 方法,得到字符串 "x"
[] + null + 1 // "null1" ==> "" + null + 1 ==> "null" + 1 ==> "null1"
"+" 運(yùn)算符執(zhí)行 number 類型轉(zhuǎn)換,先調(diào)用對(duì)象的 valueOf() 方法,結(jié)果是數(shù)組本身,不是原始類型值,所以執(zhí)行對(duì)象的 toString() 方法,得到字符串 "", 接下來執(zhí)行表達(dá)式 "" + null + 1。
0 || "0" && {} // {} ==> (0 || "0") && {} ==> (false || true) && true ==> true && true ==> true
邏輯運(yùn)算符 || 和 && 將值轉(zhuǎn)為 boolean 型,但是會(huì)返回原始值(不是 boolean)。
[1,2,3] == [1,2,3] // false
當(dāng)運(yùn)算符兩邊類型相同時(shí),不會(huì)執(zhí)行類型轉(zhuǎn)換,兩個(gè)數(shù)組的內(nèi)存地址不一樣,所以返回 false
{} + [] + {} + [1] // "0[object Object]1" ==> +[] + {} + [1] ==> 0 + {} + [1] ==> 0 + "[object Object]" + "1" ==> "0[object Object]1"
所有的操作數(shù)都不是原始類型,所以會(huì)按照從左到右的順序執(zhí)行 number 類型的隱式轉(zhuǎn)換, object 和 array 類型的 valueOf() 方法返回它們本身,所以直接忽略,執(zhí)行 toString() 方法。 這里的技巧是,第一個(gè) {} 不被視為 object,而是塊聲明語句,因此它被忽略。計(jì)算從 +[] 表達(dá)式開始,該表達(dá)式通過toString()方法轉(zhuǎn)換為空字符串,然后轉(zhuǎn)換為0。
! + [] + [] + ![] // "truefalse" ==> !(+[]) + [] + (![]) ==> !0 + [] + false ==> true + [] + false ==> true + "" + false ==> "truefalse"
一元運(yùn)算符優(yōu)先執(zhí)行,+[] 轉(zhuǎn)為 number 類型 0,![] 轉(zhuǎn)為 boolean 型 false。
new Date(0) - 0 // 0 ==> 0 - 0 ==> 0
"-" 運(yùn)算符執(zhí)行 number 類型隱式轉(zhuǎn)換對(duì)于 Date 型的值,Date.valueOf() 返回到毫秒的時(shí)間戳。
new Date(0) + 0 ==> "Thu Jan 01 1970 02:00:00 GMT+0200 (EET)" + 0 ==> "Thu Jan 01 1970 02:00:00 GMT+0200 (EET)0"
"+" 運(yùn)算符觸發(fā)默認(rèn)轉(zhuǎn)換,因此使用 toString() 方法,而不是 valueOf()。
總結(jié)查看原文
關(guān)注github每日一道面試題詳解
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/106471.html
摘要:有談?wù)劽嬖嚺c面試題對(duì)于前端面試的一些看法。動(dòng)態(tài)規(guī)劃算法的思想及實(shí)現(xiàn)方法幫大家理清動(dòng)態(tài)規(guī)劃的解決思路以及原理方法前端經(jīng)典面試題從輸入到頁面加載發(fā)生了什么這是一篇開發(fā)的科普類文章,涉及到優(yōu)化等多個(gè)方面。極客學(xué)院前端練習(xí)題道練習(xí)題,面試季練練手。 由數(shù)據(jù)綁定和排序引入的幾個(gè) JavaScript 知識(shí)點(diǎn) 在 JavaScript 的數(shù)據(jù)綁定和做簡單的表格排序中遇到的幾個(gè)知識(shí)點(diǎn) [[JS 基礎(chǔ)...
摘要:想必面試題刷的多的同學(xué)對(duì)下面這道題目不陌生,能夠立即回答出輸出個(gè),可是你真的懂為什么嗎為什么是輸出為什么是輸出個(gè)這兩個(gè)問題在我腦邊縈繞。同步任務(wù)都好理解,一個(gè)執(zhí)行完執(zhí)行下一個(gè)。本文只是我對(duì)這道面試題的一點(diǎn)思考,有誤的地方望批評(píng)指正。 想必面試題刷的多的同學(xué)對(duì)下面這道題目不陌生,能夠立即回答出輸出10個(gè)10,可是你真的懂為什么嗎?為什么是輸出10?為什么是輸出10個(gè)10?這兩個(gè)問題在我腦...
摘要:獲取的對(duì)象范圍方法獲取的是最終應(yīng)用在元素上的所有屬性對(duì)象即使沒有代碼,也會(huì)把默認(rèn)的祖宗八代都顯示出來而只能獲取元素屬性中的樣式。因此對(duì)于一個(gè)光禿禿的元素,方法返回對(duì)象中屬性值如果有就是據(jù)我測(cè)試不同環(huán)境結(jié)果可能有差異而就是。 花了很長時(shí)間整理的前端面試資源,喜歡請(qǐng)大家不要吝嗇star~ 別只收藏,點(diǎn)個(gè)贊,點(diǎn)個(gè)star再走哈~ 持續(xù)更新中……,可以關(guān)注下github 項(xiàng)目地址 https:...
摘要:下面代碼會(huì)存在什么問題,如何改進(jìn)一行代碼輸出之間的所有偶數(shù)。簡述進(jìn)程之間如何通信多路復(fù)用的作用模型的區(qū)別什么是并發(fā)和并行解釋什么是異步非阻塞的作用面試題說說你知道的命令如何查看某次提交修改的內(nèi)容答案掃碼下面的二維碼訂閱即可獲取。 引言 最近在刷面試題,所以需要看大量的 Python 相關(guān)的面試題,從大量的題目中總結(jié)了很多的知識(shí),同時(shí)也對(duì)一些題目進(jìn)行拓展了,但是在看了網(wǎng)上的大部分面試題不...
摘要:中的算法附道面試常見算法題解決方法和思路關(guān)注每日一道面試題詳解面試過程通常從最初的電話面試開始,然后是現(xiàn)場(chǎng)面試,檢查編程技能和文化契合度。值得記住的數(shù)組方法有和。一個(gè)好的解決方案是使用內(nèi)置的方法。 JavaScript中的算法(附10道面試常見算法題解決方法和思路) 關(guān)注github每日一道面試題詳解 Introduction 面試過程通常從最初的電話面試開始,然后是現(xiàn)場(chǎng)面試,檢查編程...
閱讀 3483·2019-08-30 13:15
閱讀 1423·2019-08-29 18:34
閱讀 853·2019-08-29 15:18
閱讀 3505·2019-08-29 11:21
閱讀 3281·2019-08-29 10:55
閱讀 3731·2019-08-26 10:36
閱讀 1896·2019-08-23 18:37
閱讀 1854·2019-08-23 16:57