一篇文章讓你輕松記住js的隱式轉(zhuǎn)化
前言
之前寫過一篇文章[[js讓人詬病的這些feature]]中提出過一個(gè)疑問.
這個(gè)問題一開始我想簡單了.認(rèn)為只要記住一些特性就可以了.所以直接用窮舉法來進(jìn)行規(guī)律的總結(jié).
但是當(dāng)遇到console.log(Number([])) 的結(jié)果是0, 而console.log(Number([1, 2])) 的結(jié)果是NaN.都什么亂七八糟的,里面必有蹊蹺.雖然能夠強(qiáng)背背下來, 但是作為一個(gè)有追求的程序員還是要弄明白它是怎么一回事的.
console.log({} - {}) // NaN
console.log([] - []) // 0
console.log([] - [1, 2]) // NaN
console.log([] == ![]) // true
console.log({} == {}) // false要理解上面打印的結(jié)果,就是要理解Number([]) 的值,Number([1, 2])的值, Number({})的值, 以及Boolean([])返回的值. 下面慢慢說道.
一、包裝類
Boolean()
Boolean只有兩種結(jié)果,true和false.
- Boolean結(jié)果為false的類型,我們通常稱他為 falsey, 中文叫虛值. 這些值在 [[[js讓人詬病的這些feature]] 有所提及,即,
0、null、undefined、false、''、NaN
有些文章把-0和+0算成兩個(gè)
上面這些都是原始值轉(zhuǎn)原始值.其他的都是true
如果是引用值轉(zhuǎn)原始值都為true. 還有下面這些一時(shí)間想不起來的引用類型.
Boolean(/d/) Boolean(new Error()) console.log(Boolean(Symbol()))
擴(kuò)展
還有一種容易弄混的typeof 返回結(jié)果, node環(huán)境中:
console.log(typeof Date()) console.log(typeof new Date()) console.log(Date()) // Thu Jan 13 202l2 22:29:36 GMT+0800 (中國標(biāo)準(zhǔn)時(shí)間) console.log(new Date()) // 2022-01-13T14:29:36.660Z
Number()
引用類型轉(zhuǎn)換Number
易錯(cuò)點(diǎn)出現(xiàn)在Number() 上面. 尤其是引用類型轉(zhuǎn)化為原始類型. 了解了這個(gè),開頭的例子就能夠理解了.
我們只有在知道了Number(引用類型)的規(guī)則才能夠判斷引用類型轉(zhuǎn)化為原始類型的結(jié)果什么,不然是不可能判斷得出的餓,靠猜走不遠(yuǎn).
- 我們假設(shè)有如下這么一個(gè)對(duì)象
const obj = {
toString() {
return 2
},
valueOf() {
return 1
}
}- 我們Number()包裹它
console.log(Number(obj))
打印出的結(jié)果是1. 哦,有意思的來了,
consot obj = {
toString() {
return 2
},
valueOf() {
return {}
}
}
console.log(Number(obj)) // 2讓我們讓valueOf 返回的值是對(duì)象的時(shí)候, 打印出 2 , 反之則直接打印出String原始值,再轉(zhuǎn)化為number類型.
一般來說valueof 就是代表值,沒有意義,也不用處理. 值是什么就是什么,比如說[1, 2, 3].valueOf() 直接打印就是[1, 2, 3].
我們也可以通過這個(gè)方法來解決[[讓 a == 1 && a == 2 && a == 3 成立]]的問題.
所以我們很容易得出這么一個(gè)規(guī)律: 當(dāng)valueOf 返回值是引用類型的時(shí)候, 就去拿toString 返回的值. 展開來說就是:
- 如果valueOf返回原始值,就Number包裝之后返回
- 如果valueOf返回的對(duì)象,就去toString()方法中找
- 如果toString() 返回原始值,就Number包裝之后返回
- 如果toString()返回的是對(duì)象,且是自己重寫的.那么就直接報(bào)錯(cuò)
- 如果不是充血的,那么就調(diào)用Obejct.prototye.toString方法
這里顯然還涉及到了[[原型鏈]]的問題,所以說其實(shí)隱式轉(zhuǎn)化的問題不是想象中的那么簡單的.
而我們創(chuàng)建的對(duì)象基本沒講過會(huì)創(chuàng)建這兩個(gè)方法.所以它很顯然就是繼承至Object上面的方法. 也就是說,我們?cè)谘芯窟@個(gè)問題的是,就是在研究Object.prototype.toString.call() 返回的值.
console.log(Object.prototype.tostring.call('123'));
console.log(Object.prototype.toString.call(123));
console.log(object.prototype.tostring.call(true));
console.log(Object.prototype.tostring.call(undefined));
console.log(Object.prototype.tostring.call(null));
console.log(Object.prototype.tostring.call(function){}));
console.log(Object.prototype.toString.call([1,2,3]));
console.log(Object.prototype.tostring.call(ff));打印的結(jié)果如下:
[object string] [object Number] [object Boolean] [object Undefined] [object Null] [object Functionl] [object Arrayl] [object objectl]
原始類型轉(zhuǎn)Number
console.log(Number(undefined)) // NaN
console.log(Number (null)) // 0
console.log(Number(true)) // 1
console.log(Number (false)) // 0
console.log(Number(NaN)) // NaN
console.1og(Number (Infinity))// Infinity
console.log(Number('') // 0
console.log(Number(' ') // 0
console.log(Number('123')) // 123上面沒啥好說的, 背下就行. 需要注意的是Number的值,除了我們平時(shí)使用的的數(shù)字意義之外,還有NaN、Infinity.
還有這些混淆點(diǎn)是需要注意的:
console.log((123).toString()) // 123 console.log(undefined.toString()) // 報(bào)錯(cuò) console.log(nul.toString()) // 報(bào)錯(cuò) 復(fù)制代碼
undefined 和 null 沒有包裝類, 本身又是基礎(chǔ)類型 ,自然沒有其他亂碼七糟的方法. 所以報(bào)錯(cuò).
擴(kuò)展
Argument和document
console.log(Object.toString.call(argument)) // [object Argument] console.log(Object.toString.call(document)) // [object HTMLDocument]
HTMLDocument是瀏覽器給我們提供的對(duì)象類型.
由此也可以得知Object.prototype.toString 方法的運(yùn)用之廣, 識(shí)別類型之多, 比起typeof 簡陋的返回值強(qiáng)大得多. 當(dāng)然每個(gè)都有每個(gè)使用的場(chǎng)景就是了.
手寫typeof
typeof是jscore自帶,而且也不是語法糖. 我一開始看到這個(gè)面試題的時(shí)候是懵逼的. 難道要手寫typeof的引擎代碼? 解釋一下從js第一個(gè)版本就存在的typeof null為object嗎?
但是還真有公司考這個(gè), 有點(diǎn)睿智,大聰明. 所以我看了看網(wǎng)上別人對(duì)于這的解析... 就是利用Object.prototype.toString.call()返回的結(jié)果,在進(jìn)行字符串的切割,之后后面那個(gè)單詞返回出去.
就這? 脫褲子放屁,多此一舉.
Number轉(zhuǎn)化非二進(jìn)制
Number(0xfff) // 4095 Number(070) // 56
Number可以直接識(shí)別不同位數(shù)轉(zhuǎn)化成十進(jìn)制.
parseInt和Number關(guān)系
Number('123abc') // NaN
Number('ad123') // NaN
Number(' 123') // 123而[[parseInt]]就很好的解決了這個(gè)問題,它可以說是對(duì)于Number()很好的一個(gè)補(bǔ)充
parseInt('123abc') // 123
parseInt('123asd1') // 123
parseInt('ad123') // NaN
parseInt(' 123') // 123String()
Object.prototype.toString
對(duì)于String()的使用依舊使用Number()使用的例子
const obj = {
toString() {
return 2
},
valueOf() {
return 1
}
}當(dāng)我觸發(fā)String(obj)的時(shí)候,就和Number()完全相反.
console.log(String(obj)) // 2
直接訪問的是toString()方法.
const obj = {
toString() {
return {}
},
valueOf() {
return 1
}
}
console.log(String(obj)) // 1但是如果toString() 返回的是引用類型的話, 就往valueOf()方法上面找. 可以說和Number()的完全相反,但是也符合情理 .
通過重寫toString()和valueOf()的方法來了解內(nèi)部的運(yùn)行規(guī)則是一種很好的方式.
如果不重寫的話,Object.prototype.toString.call(對(duì)象), 返回值參看Number()部分的內(nèi)容.
console.log(String({})) // [object Object]Array.prototype.toString
這個(gè)記憶上沒啥好說的, 直接把外面的[]給拆了就行.
console.log(String([1])) // '1' console.log(String([1, 2])) // '1, 2' console.log(Array.prototype.toString.call([1])) // '1' console.log(Array.prototype.toString.call([1, 2])) // '1, 2'
二、隱式轉(zhuǎn)化觸發(fā)規(guī)則
前面說了顯示轉(zhuǎn)化的規(guī)律. 下面是能夠觸發(fā)隱式轉(zhuǎn)化的規(guī)則.
和運(yùn)算符規(guī)則是和[[運(yùn)算符的優(yōu)先級(jí)]],在這里不提,可自行查閱.
布爾的隱式轉(zhuǎn)化
當(dāng)出現(xiàn)判斷的時(shí)候,會(huì)出現(xiàn)隱式轉(zhuǎn)化.
if, switch, while, for(; ;), &&, ||, !, !!, ? : 三元
number的隱式轉(zhuǎn)化
只要有小學(xué)的知識(shí)都知道運(yùn)算符,它是用于數(shù)字之間的計(jì)算的.在JavaScript中也是基本是一樣的.
+ - * % == ~~ & | ~ ^ << <<< 等, 位運(yùn)算符 、算術(shù)運(yùn)算符
隱式轉(zhuǎn)化最難的情況
== !== >= <= < >
如下例子, 也是面試的高頻題目,背下來之余,還是要知道得到這樣結(jié)果的過程.
console.log([] == ![]) // true
個(gè)人覺得隱式轉(zhuǎn)化最復(fù)雜的就是這個(gè)例子了.再復(fù)雜大不了加上優(yōu)先級(jí). 回到這個(gè)例子中, 看似比較的是兩個(gè)數(shù)組,或者說兩個(gè)特殊對(duì)象.其實(shí)不全是.來解析這個(gè)例子:
- 看到 等號(hào) 這個(gè)比較運(yùn)算法就應(yīng)該明白 等號(hào) 兩邊都要轉(zhuǎn)化成Number類型
- 從左到右的話,Number([]), [] 是引用類型,無法直接拿到原始值
- valueOf拿不到值,就走
Array.prototype.toString.call([]).從上面可以知道, 它返回的是去掉[],即字符串''. - 此時(shí)左邊為Number(''). 所以左邊返回的自然是0.
此時(shí)這個(gè)題目為0 == ![]. 接下來右邊的轉(zhuǎn)化,這就簡單了.
- 在Boolean()一節(jié)當(dāng)中,就可以知道,除了falsey之外,其他都是ture.而此時(shí)在!的加持下,[]會(huì)進(jìn)行Boolean()
- 此時(shí)右邊為true. !true就為false
- Number(false)的結(jié)果為0
由上而得出 0 == 0 的結(jié)果為true.運(yùn)用上面的知識(shí)點(diǎn)可以很好的解析問題,下面的這個(gè)例子就更加簡單了.
console.log({} == {}) // false
console.log({} != {})如果按照一樣的分析方式來解釋的話:
- 兩邊都Number()包裹住.
- toString()之后都是[obejct Object]
Number('[obejct Object]')為NaN- 所以最后轉(zhuǎn)化為
console.log(NaN == NaN)的比較
NaN和任何一個(gè)值比較都不想等
題目不難,但是綜合的東西還是有一點(diǎn)的. 這兩題解決了,隱式轉(zhuǎn)化的問題也就到頭了
三、特殊情況
最容易記住的就是字符串運(yùn)算符.
console.log(1 + '2' + '2') // '122'
console.log(1 + + '2' + '2') // '32'
console.log('A' - 'B' + '2') // 'NaN2'
console.log('A' - 'B' + 2) // NaNjs 字符串和任何數(shù)據(jù)類型想加都轉(zhuǎn)化為字符串么?可以這么說,處理symbol類型直接報(bào)錯(cuò)之外.
console.log(typeof (+ '2')) // number
還有下面undfined和null的特殊情況
console.log(undefined == null) // true console.log(NaN == NaN) // fasle
- NaN的語意是not a number,很明顯了,指的就不是一個(gè)數(shù)字
- NaN在typeof中是number類型,但是它和任何數(shù)都不想.
四、工作不要使用
2022年了,我們只需要了解==的運(yùn)行機(jī)制就夠了. 都這個(gè)年份了,不需要在重申工作中使用==還是===的問題了吧
總結(jié)
到此這篇關(guān)于js隱式轉(zhuǎn)化的文章就介紹到這了,更多相關(guān)js的隱式轉(zhuǎn)化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 簡單介紹JavaScript數(shù)據(jù)類型之隱式類型轉(zhuǎn)換
- 淺析JavaScript中的隱式類型轉(zhuǎn)換
- JavaScript隱式類型轉(zhuǎn)換
- JavaScript中運(yùn)算符規(guī)則和隱式類型轉(zhuǎn)換示例詳解
- 基于javascript 顯式轉(zhuǎn)換與隱式轉(zhuǎn)換(詳解)
- JavaScript中的一些隱式轉(zhuǎn)換和總結(jié)(推薦)
- JS面試題大坑之隱式類型轉(zhuǎn)換實(shí)例代碼
- JavaScript強(qiáng)制類型轉(zhuǎn)換和隱式類型轉(zhuǎn)換操作示例
- 對(duì)存在JavaScript隱式類型轉(zhuǎn)換的四種情況的總結(jié)(必看篇)
- 跟我學(xué)習(xí)javascript的隱式強(qiáng)制轉(zhuǎn)換
相關(guān)文章
js獲取當(dāng)前頁的URL與window.location.href簡單方法
下面小編就為大家?guī)硪黄猨s獲取當(dāng)前頁的URL與window.location.href簡單方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-02-02
JavaScript的concat方法實(shí)例代碼(數(shù)組連接)
這篇文章主要介紹了JavaScript的concat方法實(shí)例代碼,包括數(shù)組連與字符連接,需要的朋友可以參考下2023-03-03
JavaScript實(shí)現(xiàn)創(chuàng)建自定義對(duì)象的常用方式總結(jié)
這篇文章主要介紹了JavaScript實(shí)現(xiàn)創(chuàng)建自定義對(duì)象的常用方式,結(jié)合實(shí)例形式總結(jié)分析了JavaScript工廠模式、構(gòu)造函數(shù)模式、原型模式、組合模式等常用的自定義對(duì)象創(chuàng)建模式操作與使用技巧,需要的朋友可以參考下2018-07-07
js采用concat和sort將N個(gè)數(shù)組拼接起來的方法
這篇文章主要介紹了js采用concat和sort將N個(gè)數(shù)組拼接起來的方法,涉及JavaScript針對(duì)數(shù)組的合并與排序操作相關(guān)技巧,需要的朋友可以參考下2016-01-01

