[] == ![] 是多少展东?你真的知道js的類型轉(zhuǎn)換嗎

前言

這篇文章是我讀《你不知道的js(中)》總結(jié)出來(lái)的筆記哥蔚,如有疑惑或是問(wèn)題請(qǐng)?jiān)谠u(píng)論區(qū)指出~
點(diǎn)擊查看我的github原文優(yōu)化版
從js這門語(yǔ)言設(shè)計(jì)之初,他的特性————強(qiáng)制類型轉(zhuǎn)換写隶,就被眾多開(kāi)發(fā)者詬病。在很多書籍中都被稱為危險(xiǎn)的讲仰,是js設(shè)計(jì)的一大缺陷慕趴。但大多數(shù)人認(rèn)為這個(gè)特性在開(kāi)發(fā)中有利有弊,需要合理地使用它鄙陡。

自我檢測(cè)

[] == ![] // -> true

如果你的答案為false冕房,你需要仔細(xì)閱讀一下本文的D部分~~

顯式類型轉(zhuǎn)換和隱式類型轉(zhuǎn)換

強(qiáng)制轉(zhuǎn)換經(jīng)常發(fā)生在動(dòng)態(tài)類型語(yǔ)言運(yùn)行時(shí)。我們經(jīng)常會(huì)寫類型轉(zhuǎn)換柔吼,如:

var a=1 
var b=a+'' // 隱式 '1'
var c=String(a) // 顯式 '1'

這里的隱式和顯式是相對(duì)于開(kāi)發(fā)者而言的毒费。可以從代碼中看出來(lái)類型轉(zhuǎn)換的是顯式愈魏,反則為隱式觅玻。

A.抽象值操作

1.ToString

非字符串->字符串。

基本類型

null -> 'null'
undefined -> 'undefined'
true -> 'true'
1 -> '1'
1 * 1 000 000 000 000 000 000 000 -> '1e+21'

復(fù)雜類型

當(dāng)對(duì)象有自己的toString()方法培漏,字符串化時(shí)就會(huì)調(diào)用該方法溪厘,使用其返回值。

const obj={
    a:'test',
    toString(){
        return 'yeah~~'
    }
}
//沒(méi)有自定義的toString()方法應(yīng)該返回[object Object]111牌柄,
console.log(obj+'111') // yeah~~111

JSON字符串化

對(duì)于大多數(shù)簡(jiǎn)單值來(lái)說(shuō)畸悬,JSON.stringify()toString()的效果基本相同,序列化的結(jié)果總是字符串珊佣。有一個(gè)比較特殊的情況:

JSON.stringify('hello') // ""hello""  含有雙引號(hào)的字符串

對(duì)于undefined蹋宦、function、symbol來(lái)說(shuō)會(huì)返回undefined咒锻,在數(shù)組中返回null冷冗、在對(duì)象中自動(dòng)忽略。

JSON.stringify(undefined) // undefined
JSON.stringify(function(){}) // undefined
JSON.stringify([function(){},2]) // "[null,2]"
JSON.stringify({a:function(){},b:2}) // "{"b":2}"
const obj={
    a:'test',
    toJSON(){
        return 'yeah~~'
    }
}
console.log(JSON.stringify(obj))

答案:

"yeah~~"

2.ToNumber

基本類型

true -> 1
false -> 0
undefined -> NaN
null -> 0

處理字符串失敗時(shí)返回NaN惑艇。

復(fù)雜類型

對(duì)象(包括數(shù)組)蒿辙,先被轉(zhuǎn)換為相應(yīng)的基本類型值拇泛,如果返回的是非數(shù)字的基本類型值,則按照上面的規(guī)則強(qiáng)制轉(zhuǎn)換為數(shù)字思灌。

將值轉(zhuǎn)換為相應(yīng)的基本類型值俺叭,先檢查該值是否有valueOf()方法,有并且返回基本類型值泰偿,則使用該值進(jìn)行強(qiáng)制類型轉(zhuǎn)換熄守;沒(méi)有就使用toString()的返回值進(jìn)行強(qiáng)制轉(zhuǎn)換。如果以上都不返回基類型值甜奄,產(chǎn)生TypeError錯(cuò)誤柠横。

const obj={
    toString(){
        return '1'
    }
}
console.log({}) // NaN
console.log(Number(obj)) // 1

注意使用Object.create(null)創(chuàng)建的對(duì)象窃款,無(wú)法進(jìn)行強(qiáng)制轉(zhuǎn)換课兄!是因?yàn)槠?code>[[Prototype]]為空,沒(méi)有valueOf()toString()方法晨继。

3.ToBoolean

假值(falsy value)

js中的值可被分為兩類:可被強(qiáng)制轉(zhuǎn)換為false的值烟阐,和其他(可以被強(qiáng)制轉(zhuǎn)換為true的值)。

以下這些為假值:

undefined
null
fasle
+0 -0 NaN
""

雖然沒(méi)有明確規(guī)定紊扬,我們可以默認(rèn)除了這些值以外的所有值為真值蜒茄。

B.顯式強(qiáng)制類型轉(zhuǎn)換

字符串和數(shù)字之間的顯式轉(zhuǎn)換

一般通過(guò)String()Number()這兩個(gè)內(nèi)建函數(shù)實(shí)現(xiàn)的。如:

String(1) // "1"
Number('1.25') // 1.25

通過(guò)一元運(yùn)算符以及toString()也被認(rèn)為是顯示強(qiáng)制類型轉(zhuǎn)換餐屎。

+'25' // 25

日期顯示轉(zhuǎn)換為數(shù)字

一元運(yùn)算符有一個(gè)常用的用途是檀葛,將Date對(duì)象強(qiáng)制轉(zhuǎn)換為Unix時(shí)間戳,如:

+new Date() // 1516625381333

我們也可以使用更顯式的方法:

new Date().getTime() // 1516625518125

最好還是使用Date.now()來(lái)獲得當(dāng)前的時(shí)間戳腹缩。

位操作符~

~運(yùn)算符屿聋,按位非,反轉(zhuǎn)操作符的比特位藏鹊。位操作符會(huì)強(qiáng)制操作數(shù)使用32位格式润讥,通過(guò)ToInt32實(shí)現(xiàn)(ToInt32先執(zhí)行ToNUmber強(qiáng)制轉(zhuǎn)換,之后再執(zhí)行ToInt32)盘寡。如果你不太明白他的運(yùn)算機(jī)制楚殿,請(qǐng)記住一個(gè)公式:

~4 -> -5
~x  =>  -(x+1)

~在日常開(kāi)發(fā)中很少會(huì)用到,但在我們處理indexOf()時(shí)竿痰,可以將結(jié)果強(qiáng)制轉(zhuǎn)換為真/假值脆粥。

const str='hello'
str.indexOf('a') // -1
~str.indexOf('a') //0  -> 假值

~~x還可以用來(lái)截除小數(shù)部分,如:

~~-22.8 -> -22

顯式解析數(shù)字字符串

解析和轉(zhuǎn)換的區(qū)別

使用parseInt()將字符串解析為數(shù)字影涉,它與Number的作用并不一樣:

  1. parseInt只能解析字符串变隔,傳入其他類型參數(shù),如true常潮、function(){}等弟胀,返回NaN。
  2. parseInt可以解析含有非數(shù)字字符的字符串,如parseInt('2px')將會(huì)解析為2孵户,Number則會(huì)返回NaN萧朝。

對(duì)于parseInt有一個(gè)經(jīng)典的例子,

parseInt(1/0,19) -> 18

這是因?yàn)?/0為Infinity夏哭,先被轉(zhuǎn)化為字符串'Infinity'检柬,第一個(gè)字符為i,在js中有效數(shù)字為09和0i竖配,所以之后的n不會(huì)被解析何址,只解析到i為止,i為第18位进胯,所以輸出為18.

顯式轉(zhuǎn)換為布爾值

和上面的Number(),String()一樣用爪,Boolean()為顯式的ToBoolean強(qiáng)制類型轉(zhuǎn)換。但這個(gè)在開(kāi)發(fā)中并不常用胁镐,通常使用!!來(lái)進(jìn)行強(qiáng)制類型轉(zhuǎn)換偎血。

if()...上下文中,如沒(méi)有使用Boolean()!!轉(zhuǎn)成布爾值盯漂,則會(huì)進(jìn)行隱式轉(zhuǎn)換颇玷。但還是建議使用顯式轉(zhuǎn)換,讓代碼可讀性更高就缆。

C.隱式強(qiáng)制類型轉(zhuǎn)換

1.字符串和數(shù)字之間的隱式轉(zhuǎn)換

+/-操作符

+如何判斷是進(jìn)行字符串拼接帖渠,還是數(shù)值加法呢?

+的其中一個(gè)操作符為字符串(或是通過(guò)ToPrimitive抽象操作后轉(zhuǎn)換為字符串的值)則進(jìn)行字符串拼接竭宰,否則執(zhí)行數(shù)字加法空郊。

所以,通常上我們將空字符串與數(shù)值進(jìn)行拼接羞延,將其轉(zhuǎn)換為字符串渣淳。

const a='2'
const b=a-0
b // -> 2

通過(guò)-也可將a強(qiáng)制轉(zhuǎn)換為數(shù)字,或者使用a*1a/1伴箩,因?yàn)檫@兩個(gè)運(yùn)算符只適用于數(shù)字入愧,所以比較少見(jiàn)。

const a=[1]
const b=[3]
a-b // -> -2

2.隱式類型轉(zhuǎn)換為布爾值

在以下情況中嗤谚,非布爾值會(huì)被隱式轉(zhuǎn)換為布爾值棺蛛。

  1. if()中的判斷表達(dá)式
  2. for(;;)中的條件判斷表達(dá)式
  3. while(...)和do..while(..)循環(huán)中的條件表達(dá)式
  4. ? : 中的條件判斷表達(dá)式
  5. 邏輯運(yùn)算符 || 和 && 左邊的操作數(shù)。

但&&和||返回的值并不一定是布爾值巩步,而是兩個(gè)操作書中其中的一個(gè)旁赊。如:

123||'hello' // 123
42&&'abc' // 'abc'
null || 'hello' // ->'hello'
null && 'hello' // ->null

3.Symbol的強(qiáng)制類型轉(zhuǎn)換

ES6允許從符號(hào)到字符串得顯示類型轉(zhuǎn)換,但使用隱式轉(zhuǎn)換會(huì)報(bào)錯(cuò)椅野。

const s1=Symbol('test')
String(s1) -> "Symbol(test)"
''+s1 -> Uncaught TypeError: Cannot convert a Symbol value to a string

同時(shí)终畅,Symbol類型也不能被轉(zhuǎn)換為數(shù)字(無(wú)論是顯式還是隱式)籍胯,但可以被轉(zhuǎn)換為布爾值。

D.寬松相等( == )和嚴(yán)格相等( === )

==允許在相等比較中進(jìn)行強(qiáng)制類型轉(zhuǎn)換离福,但===則不允許杖狼。

寬松相等的轉(zhuǎn)換規(guī)則(==)

  1. 對(duì)于基本類型:兩個(gè)值的類型相同,則比較是否相等妖爷。
    除了NaN(NaN是js中唯一不等于自身的值)和+0/-0(+0 === -0)蝶涩。類型不同的兩個(gè)值參考第三條。
  2. 對(duì)于對(duì)象(包括函數(shù)和數(shù)組):他們指向同一引用時(shí)絮识,即視為相等绿聘,不發(fā)生強(qiáng)制轉(zhuǎn)換。
  3. 在比較兩個(gè)不同類型的值時(shí)次舌,會(huì)發(fā)生隱式類型轉(zhuǎn)換熄攘,將其轉(zhuǎn)為相同的類型后再比較。

字符串和數(shù)字之間的相等比較

const a='12'
const b=12
a==b //true
a===b //false

規(guī)則為:==兩邊垃它,哪邊為數(shù)值類型鲜屏,則另一邊轉(zhuǎn)為數(shù)值類型烹看。

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

const a='12'
const b=true
a==b // false  a為真值国拇,為什么返回false

因?yàn)樵?code>==兩邊,哪邊為布爾類型惯殊,哪邊轉(zhuǎn)為數(shù)值類型=戳摺!
同樣土思,a==false也會(huì)返回false务热,因?yàn)檫@里的布爾值會(huì)被強(qiáng)制轉(zhuǎn)換為數(shù)字0.

null和undefined之間的相等比較

只要記住:

null == undefined //true
null === undefined //false

對(duì)象和非對(duì)象之間的相等比較

對(duì)于布爾值和對(duì)象之間的比較己儒,先把布爾值轉(zhuǎn)換為數(shù)值類型崎岂。
數(shù)值或字符串與對(duì)象之間的比較,對(duì)象先會(huì)調(diào)用ToPromitive抽象操作闪湾,之后再轉(zhuǎn)為數(shù)值進(jìn)行比較冲甘。

const a=12
const b=[12]
a==b //true
b->'12'->12

const c=Object(null)
c==null //fasle 這里c被轉(zhuǎn)換為空對(duì)象{}

const d=Object(undefined)
d==undefined // fasle 這里d被轉(zhuǎn)換為空對(duì)象{}

const e=Object(NaN)
e==NaN // fasle 這里e被轉(zhuǎn)換為Number(NaN) -> NaN 但NaN不等于自身,所以為false

幾個(gè)典型的坑

// 小坑
"0" == false // -> true  這里false先被轉(zhuǎn)為0途样,"0"也會(huì)轉(zhuǎn)為0江醇,所以為true
"0" == "" // -> false 兩個(gè)都是字符串類型,直接比較
0 == '' // -> true 空字符串直接轉(zhuǎn)為0
false == [] // -> true false先轉(zhuǎn)為0何暇;[]空數(shù)組轉(zhuǎn)為''陶夜,之后ToNumber操作轉(zhuǎn)為0

// 大坑
[] == ![] // -> true []  這里![]先被強(qiáng)制轉(zhuǎn)換為false,變成[]與fasle的比較裆站,之后fasle->0条辟;[]->''->0黔夭,所以為true。
2=[2] // -> true [2]->'2'->2 所以為true
''==[null] // true [null]->''
0=='\n' // -> true '\n'->''->0
'true'==true // -> false true->0;'true'->NaN羽嫡,所以為false

如果你還是一頭霧水的話纠修,請(qǐng)仔細(xì)閱讀D部分這幾種相互比較的規(guī)則和C部分的隱式類型轉(zhuǎn)換。只要記住厂僧,遇到兩個(gè)不同類型的值扣草,轉(zhuǎn)換優(yōu)先順序?yàn)椴紶栔?gt;對(duì)象>字符串>數(shù)字;每一步的轉(zhuǎn)換到相同類型的值即停止轉(zhuǎn)換颜屠,進(jìn)行比較判斷辰妙。

E.抽象關(guān)系比較

出現(xiàn)非字符串就先轉(zhuǎn)為數(shù)字類型;如果兩者都為字符串甫窟,按照字母順序來(lái)比較密浑,如:

['22']<['023'] // -> false 這里并不轉(zhuǎn)為數(shù)字,0在字母順序上小于2粗井,所以為false
22<['023'] // -> true

對(duì)于對(duì)象來(lái)說(shuō)尔破,也同樣是轉(zhuǎn)換成字符串,再進(jìn)行比較浇衬,如:

const a={a:1}
const b={a:2}
a>b // -> false
a<b // -> false
a==b // -> false
a<=b // -> true
a>=b // -> true

這個(gè)例子比較奇怪懒构,雖然他們轉(zhuǎn)成字符串都為[Object Object],但兩個(gè)對(duì)象的比較并不是轉(zhuǎn)為字符串耘擂,而是看他們的引用是否指向同一值胆剧。這里<=被處理為!>,所以為true醉冤; >=同理秩霍。

總結(jié)

在處理強(qiáng)制類型轉(zhuǎn)換時(shí)要十分消息,尤其是隱式強(qiáng)制類型轉(zhuǎn)換蚁阳。寫代碼的時(shí)候铃绒,要知道什么時(shí)候要寫顯式類型轉(zhuǎn)換,什么時(shí)候用隱式螺捐,努力讓代碼更清晰可讀~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末颠悬,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子归粉,更是在濱河造成了極大的恐慌椿疗,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件糠悼,死亡現(xiàn)場(chǎng)離奇詭異届榄,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)倔喂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門铝条,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)靖苇,“玉大人,你說(shuō)我怎么就攤上這事班缰∠捅冢” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵埠忘,是天一觀的道長(zhǎng)脾拆。 經(jīng)常有香客問(wèn)我,道長(zhǎng)莹妒,這世上最難降的妖魔是什么名船? 我笑而不...
    開(kāi)封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮旨怠,結(jié)果婚禮上渠驼,老公的妹妹穿的比我還像新娘。我一直安慰自己鉴腻,他們只是感情好迷扇,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著爽哎,像睡著了一般蜓席。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上倦青,一...
    開(kāi)封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天瓮床,我揣著相機(jī)與錄音,去河邊找鬼产镐。 笑死,一個(gè)胖子當(dāng)著我的面吹牛踢步,可吹牛的內(nèi)容都是我干的癣亚。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼获印,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了玻孟?” 一聲冷哼從身側(cè)響起鳍征,我...
    開(kāi)封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎匣掸,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體霎匈,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡送爸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年袭厂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嵌器。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡爽航,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出讥珍,到底是詐尸還是另有隱情,我是刑警寧澤趟卸,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布锄列,位于F島的核電站惯悠,受9級(jí)特大地震影響邻邮,放射性物質(zhì)發(fā)生泄漏筒严。R本人自食惡果不足惜情萤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望娶视。 院中可真熱鬧泉蝌,春花似錦揩晴、人聲如沸贪磺。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)刹前。三九已至,卻和暖如春喇喉,著一層夾襖步出監(jiān)牢的瞬間拣技,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工徐绑, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留莫辨,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓盘榨,卻偏偏與公主長(zhǎng)得像敞映,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子振愿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 值類型轉(zhuǎn)換將值從一種類型轉(zhuǎn)換為另一種類型通常稱為類型轉(zhuǎn)換冕末,這是顯示的情況侣颂;隱式的情況稱為強(qiáng)制類型轉(zhuǎn)換。JavaSc...
    xpwei閱讀 3,545評(píng)論 0 5
  • 第2章 基本語(yǔ)法 2.1 概述 基本句法和變量 語(yǔ)句 JavaScript程序的執(zhí)行單位為行(line)蔑舞,也就是一...
    悟名先生閱讀 4,149評(píng)論 0 13
  • 值類型轉(zhuǎn)換 將值從一種類型轉(zhuǎn)換為另一種類型通常稱為類型轉(zhuǎn)換嘹屯,這是顯式的情況;隱式的情況稱為強(qiáng)制類型轉(zhuǎn)換 類型轉(zhuǎn)換發(fā)...
    俗三瘋閱讀 597評(píng)論 0 0
  • 最近在讀一本小說(shuō)钧栖,名字叫《去你的婆翔,生活》這本書主要講述了作者通過(guò)與畫家盧西安·弗洛伊德共進(jìn)早餐,而了解他的生活和作...
    楊楊楊菇?jīng)?/span>閱讀 258評(píng)論 0 1
  • 幼兒園 女兒潭陪,在秋天的陽(yáng)光下 高聳的樓宇最蕾,泛青的山 人聲鼎沸的廣場(chǎng) 在你看來(lái)都是幼兒園 都是你準(zhǔn)備拋灑歡樂(lè)的地方 ...
    惟崗閱讀 252評(píng)論 0 0