亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

通過(guò)一張簡(jiǎn)單的圖,讓你徹底地、永久地搞懂JS的==運(yùn)算

testbird / 711人閱讀

摘要:一有和無(wú)在圖中,值的六種類(lèi)型用藍(lán)底色的矩形表示。想一下在語(yǔ)言中,根本沒(méi)有布爾類(lèi)型,通常用來(lái)表示邏輯真假的正是整數(shù)和。根據(jù)圖,需要將布爾類(lèi)型轉(zhuǎn)為數(shù)字類(lèi)型,而轉(zhuǎn)為數(shù)字的結(jié)果是,所以表達(dá)式變?yōu)閮蓚€(gè)操作數(shù)變成了對(duì)象類(lèi)型數(shù)字類(lèi)型。

大家知道,==是JavaScript中比較復(fù)雜的一個(gè)運(yùn)算符。它的運(yùn)算規(guī)則奇怪,容易讓人犯錯(cuò),從而成為JavaScript中“最糟糕的特性”之一。

在仔細(xì)閱讀了ECMAScript規(guī)范的基礎(chǔ)上,我畫(huà)了一張圖,我想通過(guò)它你會(huì)徹底地搞清楚關(guān)于==的一切。同時(shí),我也試圖通過(guò)此文向大家證明==并不是那么糟糕的東西,它很容易掌握,甚至看起來(lái)很合理。

先上圖:


圖1 ==運(yùn)算規(guī)則的圖形化表示

==運(yùn)算規(guī)則的精確描述在此:The Abstract Equality Comparison Algorithm。但是,這么復(fù)雜的描述,你確定看完后腦子不暈?確定立馬就能拿它指導(dǎo)實(shí)踐?

肯定不行,規(guī)范畢竟是給JavaScript運(yùn)行環(huán)境的開(kāi)發(fā)人員看的(比如V8引擎的開(kāi)發(fā)人員們),而不是給語(yǔ)言的使用者看的。而上圖正是將規(guī)范中復(fù)雜的描述翻譯成了更容易看懂的形式。

在詳細(xì)介紹圖1中的每個(gè)部分前,我們來(lái)復(fù)習(xí)一下JS中關(guān)于類(lèi)型的知識(shí):

JS中的值有兩種類(lèi)型:原始類(lèi)型(Primitive)、對(duì)象類(lèi)型(Object)。

基本類(lèi)型包括:Undefined、Null、Boolean、Number和String等五種。

Undefined類(lèi)型和Null類(lèi)型的都只有一個(gè)值,即undefinednull;Boolean類(lèi)型有兩個(gè)值:truefalse;Number類(lèi)型的值有很多很多;String類(lèi)型的值理論上有無(wú)數(shù)個(gè)。

所有對(duì)象都有valueOf()toString()方法,它們繼承自Object,當(dāng)然也可能被子類(lèi)重寫(xiě)。

現(xiàn)在考慮表達(dá)式:

x == y

其中xy是上述六種類(lèi)型中某一種類(lèi)型的值。

當(dāng)xy的類(lèi)型相同時(shí),x == y可以轉(zhuǎn)化為x === y,而后者是很簡(jiǎn)單的(唯一需要注意的可能是NaN),所以下面我們只考慮xy的類(lèi)型不同的情況。

一. 有和無(wú)

在圖1中,JavaScript值的六種類(lèi)型用藍(lán)底色的矩形表示。它們首先被分成了兩組:

String、Number、Boolean和Object (對(duì)應(yīng)左側(cè)的大矩形框)

Undefined和Null (對(duì)應(yīng)右側(cè)的矩形框)

分組的依據(jù)是什么?我們來(lái)看一下,右側(cè)的Undefined和Null是用來(lái)表示不確定、無(wú)或者的,而右側(cè)的四種類(lèi)型都是確定的、非空。我們可以這樣說(shuō):

左側(cè)是一個(gè)存在的世界,右側(cè)是一個(gè)的世界。

所以,左右兩個(gè)世界中的任意值做==比較的結(jié)果都是false是很合理的。(見(jiàn)圖1中連接兩個(gè)矩形的水平線上標(biāo)的false)

二. 空和空

JavaScript中的undefinednull是另一個(gè)經(jīng)常讓我們崩潰的地方。通常它被認(rèn)為是一個(gè)設(shè)計(jì)缺陷,這一點(diǎn)我們不去深究。不過(guò)我曾聽(tīng)說(shuō),JavaScript的作者最初是這樣想的:

假如你打算把一個(gè)變量賦予對(duì)象類(lèi)型的值,但是現(xiàn)在還沒(méi)有賦值,那么你可以用null表示此時(shí)的狀態(tài)(證據(jù)之一就是typeof null 的結(jié)果是"object");相反,假如你打算把一個(gè)變量賦予原始類(lèi)型的值,但是現(xiàn)在還沒(méi)有賦值,那么你可以用undefined表示此時(shí)的狀態(tài)。

不管這個(gè)傳聞是否可信,它們兩者做==比較的結(jié)果是true是很合理的。(見(jiàn)圖1中右側(cè)垂直線上標(biāo)的true)

在進(jìn)行下一步之前,我們先來(lái)說(shuō)一下圖1中的兩個(gè)符號(hào):大寫(xiě)字母N和P。這兩個(gè)符號(hào)并不是PN結(jié)中正和負(fù)的意思。而是:

N表示ToNumber操作,即將操作數(shù)轉(zhuǎn)為數(shù)字。它是規(guī)范中的抽象操作,但我們可以用JS中的Number()函數(shù)來(lái)等價(jià)替代。

P表示ToPrimitive操作,即將操作數(shù)轉(zhuǎn)為原始類(lèi)型的值。它也是規(guī)范中的抽象操作,同樣也可以翻譯成等價(jià)的JS代碼。不過(guò)稍微復(fù)雜一些,簡(jiǎn)單說(shuō)來(lái),對(duì)于一個(gè)對(duì)象obj

ToPrimitive(obj)等價(jià)于:先計(jì)算obj.valueOf(),如果結(jié)果為原始值,則返回此結(jié)果;否則,計(jì)算obj.toString(),如果結(jié)果是原始值,則返回此結(jié)果;否則,拋出異常。

注:此處有個(gè)例外,即Date類(lèi)型的對(duì)象,它會(huì)先調(diào)用toString()方法,后調(diào)用valueOf()方法。

在圖1中,標(biāo)有N或P的線表示:當(dāng)它連接的兩種類(lèi)型的數(shù)據(jù)做==運(yùn)算時(shí),標(biāo)有N或P的那一邊的操作數(shù)要先執(zhí)行ToNumber或ToPrimitive變換。

三. 真與假

從圖1可以看出,當(dāng)布爾值與其他類(lèi)型的值作比較時(shí),布爾值會(huì)轉(zhuǎn)化為數(shù)字,具體來(lái)說(shuō)

true -> 1
false -> 0

這一點(diǎn)也不需浪費(fèi)過(guò)多口舌。想一下在C語(yǔ)言中,根本沒(méi)有布爾類(lèi)型,通常用來(lái)表示邏輯真假的正是整數(shù)1和0。

四. 字符的序列

在圖1中,我們把String和Number類(lèi)型分成了一組。為什么呢?在六種類(lèi)型中,String和Number都是字符的序列(至少在字面上如此)。字符串是所有合法的字符的序列,而數(shù)字可以看成是符合特定條件的字符的序列。所以,數(shù)字可以看成字符串的一個(gè)子集。

根據(jù)圖1,在字符串和數(shù)字做==運(yùn)算時(shí),需要使用ToNumber操作,把字符串轉(zhuǎn)化為數(shù)字。假設(shè)x是字符串,y是數(shù)字,那么:

x == y -> Number(x) == y

那么字符串轉(zhuǎn)化為數(shù)字的規(guī)則是怎樣的呢?規(guī)范中描述得很復(fù)雜,但是大致說(shuō)來(lái),就是把字符串兩邊的空白字符去掉,然后把兩邊的引號(hào)去掉,看它能否組成一個(gè)合法的數(shù)字。如果是,轉(zhuǎn)化結(jié)果就是這個(gè)數(shù)字;否則,結(jié)果是NaN。例如:

Number("123") // 結(jié)果123
Number("1.2e3") // 結(jié)果1200
Number("123abc") // 結(jié)果NaN
Number("
	123vf") // 結(jié)果123

當(dāng)然也有例外,比如空白字符串轉(zhuǎn)化為數(shù)字的結(jié)果是0。即

Number("") // 結(jié)果0
Number("
	 vf") // 結(jié)果0
五. 單純與復(fù)雜

原始類(lèi)型是一種單純的類(lèi)型,它們直接了當(dāng)、容易理解。然而缺點(diǎn)是表達(dá)能力有限,難以擴(kuò)展,所以就有了對(duì)象。對(duì)象是屬性的集合,而屬性本身又可以是對(duì)象。所以對(duì)象可以被構(gòu)造得任意復(fù)雜,足以表示各種各樣的事物。

但是,有時(shí)候事情復(fù)雜了也不是好事。比如一篇冗長(zhǎng)的論文,并不是每個(gè)人都有時(shí)間、有耐心或有必要從頭到尾讀一遍,通常只了解其中心思想就夠了。于是論文就有了關(guān)鍵字、概述。JavaScript中的對(duì)象也一樣,我們需要有一種手段了解它的主要特征,于是對(duì)象就有了toString()valueOf()方法。

toString()方法用來(lái)得到對(duì)象的一段文字描述;而valueOf()方法用來(lái)得到對(duì)象的特征值。

當(dāng)然,這只是我自己的理解。顧名思義,toString()方法傾向于返回一個(gè)字符串。那么valueOf()方法呢?根據(jù)規(guī)范中的描述,它傾向于返回一個(gè)數(shù)字——盡管內(nèi)置類(lèi)型中,valueOf()方法返回?cái)?shù)字的只有NumberDate。

根據(jù)圖1,當(dāng)一個(gè)對(duì)象與一個(gè)非對(duì)象比較時(shí),需要將對(duì)象轉(zhuǎn)化為原始類(lèi)型(雖然與布爾類(lèi)型比較時(shí),需要先將布爾類(lèi)型變成數(shù)字類(lèi)型,但是接下來(lái)還是要將對(duì)象類(lèi)型變成原始類(lèi)型)。這也是合理的,畢竟==是不嚴(yán)格的相等比較,我們只需要取出對(duì)象的主要特征來(lái)參與運(yùn)算,次要特征放在一邊就行了。

六. 萬(wàn)物皆數(shù)

我們回過(guò)頭來(lái)看一下圖1。里面標(biāo)有N或P的那幾條連線是沒(méi)有方向的。假如我們?cè)谶@些線上標(biāo)上箭頭,使得連線從標(biāo)有N或P的那一端指向另一端,那么會(huì)得到(不考慮undefined和null):


圖2 ==運(yùn)算過(guò)程中類(lèi)型轉(zhuǎn)化的趨勢(shì)

發(fā)現(xiàn)什么了嗎?對(duì),在運(yùn)算過(guò)程中,所有類(lèi)型的值都有一種向數(shù)字類(lèi)型轉(zhuǎn)化的趨勢(shì)。畢竟曾經(jīng)有名人說(shuō)過(guò):

萬(wàn)物皆數(shù)。

七. 舉個(gè)栗子

前面廢話太多了,這里還是舉個(gè)例子,來(lái)證明圖1確實(shí)是方便有效可以指導(dǎo)實(shí)踐的。

例,計(jì)算下面表達(dá)式的值:

[""] == false

首先,兩個(gè)操作數(shù)分別是對(duì)象類(lèi)型、布爾類(lèi)型。根據(jù)圖1,需要將布爾類(lèi)型轉(zhuǎn)為數(shù)字類(lèi)型,而false轉(zhuǎn)為數(shù)字的結(jié)果是0,所以表達(dá)式變?yōu)椋?/p>

[""] == 0

兩個(gè)操作數(shù)變成了對(duì)象類(lèi)型、數(shù)字類(lèi)型。根據(jù)圖1,需要將對(duì)象類(lèi)型轉(zhuǎn)為原始類(lèi)型:

首先調(diào)用[].valueOf(),由于數(shù)組的valueOf()方法返回自身,所以結(jié)果不是原始類(lèi)型,繼續(xù)調(diào)用[].toString()。

對(duì)于數(shù)組來(lái)說(shuō),toString()方法的算法,是將每個(gè)元素都轉(zhuǎn)為字符串類(lèi)型,然后用逗號(hào)","依次連接起來(lái),所以最終結(jié)果是空字符串"",它是一個(gè)原始類(lèi)型的值。

此時(shí),表達(dá)式變?yōu)椋?/p>

"" == 0

兩個(gè)操作數(shù)變成了字符串類(lèi)型、數(shù)字類(lèi)型。根據(jù)圖1,需要將字符串類(lèi)型轉(zhuǎn)為數(shù)字類(lèi)型,前面說(shuō)了空字符串變成數(shù)字是0。于是表達(dá)式變?yōu)椋?/p>

0 == 0

到此為止,兩個(gè)操作數(shù)的類(lèi)型終于相同了,結(jié)果明顯是true

從這個(gè)例子可以看出,要想掌握==運(yùn)算的規(guī)則,除了牢記圖1外,還需要記住那些內(nèi)置對(duì)象的toString()valueOf()方法的規(guī)則。包括Object、Array、Date、Number、String、Boolean等,幸好這沒(méi)有什么難度。

八. 再次變形

其實(shí),圖一還不夠完美。為什么呢?因?yàn)閷?duì)象與字符串/數(shù)字比較時(shí)都由對(duì)象來(lái)轉(zhuǎn)型,但是與同樣是原始類(lèi)型的布爾類(lèi)型比較時(shí)卻需要布爾類(lèi)型轉(zhuǎn)型。實(shí)際上,只要稍稍分析一下,全部讓對(duì)象來(lái)轉(zhuǎn)為原始類(lèi)型也是等價(jià)的。所以我們得到了最終的更加完美的圖形:


圖3 更完美的==運(yùn)算規(guī)則的圖形化表示

有一個(gè)地方可能讓你疑惑:為什么Boolean與String之間標(biāo)了兩個(gè)N?雖然按照規(guī)則應(yīng)該是由Boolean轉(zhuǎn)為數(shù)字,但是下一步String就要轉(zhuǎn)為數(shù)字了,所以干脆不如兩邊同時(shí)轉(zhuǎn)成數(shù)字。

九. 總結(jié)一下

前面說(shuō)得很亂,根據(jù)我們得到的最終的圖3,我們總結(jié)一下==運(yùn)算的規(guī)則:

undefined == null,結(jié)果是true。且它倆與所有其他值比較的結(jié)果都是false。

String == Boolean,需要兩個(gè)操作數(shù)同時(shí)轉(zhuǎn)為Number。

String/Boolean == Number,需要String/Boolean轉(zhuǎn)為Number。

Object == Primitive,需要Object轉(zhuǎn)為Primitive(具體通過(guò)valueOf和toString方法)。

瞧見(jiàn)沒(méi)有,一共只有4條規(guī)則!是不是很清晰、很簡(jiǎn)單。

PS:最后,把圖改了一下,僅供娛樂(lè) : )

OK,結(jié)束了。如果你覺(jué)得這篇文章對(duì)你有用,請(qǐng)點(diǎn)贊,讓更多的人看到。
另外,文章中的謬誤,請(qǐng)不吝指出。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/86382.html

相關(guān)文章

  • JavaScript深入淺出

    摘要:理解的函數(shù)基礎(chǔ)要搞好深入淺出原型使用原型模型,雖然這經(jīng)常被當(dāng)作缺點(diǎn)提及,但是只要善于運(yùn)用,其實(shí)基于原型的繼承模型比傳統(tǒng)的類(lèi)繼承還要強(qiáng)大。中文指南基本操作指南二繼續(xù)熟悉的幾對(duì)方法,包括,,。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。 怎樣使用 this 因?yàn)楸救藢儆趥吻岸?,因此文中只看懂?8 成左右,希望能夠給大家?guī)?lái)幫助....(據(jù)說(shuō)是阿里的前端妹子寫(xiě)的) this 的值到底...

    blair 評(píng)論0 收藏0
  • 7月份前端資源分享

    摘要:更多資源請(qǐng)文章轉(zhuǎn)自月份前端資源分享的作用數(shù)組元素隨機(jī)化排序算法實(shí)現(xiàn)學(xué)習(xí)筆記數(shù)組隨機(jī)排序個(gè)變態(tài)題解析上個(gè)變態(tài)題解析下中的數(shù)字前端開(kāi)發(fā)筆記本過(guò)目不忘正則表達(dá)式聊一聊前端存儲(chǔ)那些事兒一鍵分享到各種寫(xiě)給剛?cè)腴T(mén)的前端工程師的前后端交互指南物聯(lián)網(wǎng)世界的 更多資源請(qǐng)Star:https://github.com/maidishike... 文章轉(zhuǎn)自:https://github.com/jsfr...

    pingan8787 評(píng)論0 收藏0
  • 從[]==![]為true來(lái)剖析JavaScript各種蛋疼類(lèi)型轉(zhuǎn)換

    摘要:將他們放在堆中是為了不影響棧的效率。所以簡(jiǎn)單數(shù)據(jù)類(lèi)型的值直接存放在棧中??梢詫?duì)比上面那張圖默認(rèn)是調(diào)用方法的依,于是等于空字符串??兆址袊?guó)標(biāo)準(zhǔn)時(shí)間方法返回對(duì)象的原始值,可能是字符串?dāng)?shù)值或值等,看具體的對(duì)象。,需要兩個(gè)操作數(shù)同時(shí)轉(zhuǎn)為。 你是否在面試中遇到過(guò)各種奇葩和比較細(xì)節(jié)的問(wèn)題? []==[] //false []==![] //true {}==!{} //false {}==![...

    Jeff 評(píng)論0 收藏0
  • 線程安全(上)--徹底搞懂volatile關(guān)鍵字

    摘要:此時(shí),就出現(xiàn)了線程不安全問(wèn)題了。因?yàn)榈某跏贾禃?huì)是因此,重排序是有可能導(dǎo)致線程安全問(wèn)題的。真的能完全保證一個(gè)變量的線程安全嗎我們通過(guò)上面的講解,發(fā)現(xiàn)關(guān)鍵字還是挺有用的,不但能夠保證變量的可見(jiàn)性,還能保證代碼的有序性。 對(duì)于volatile這個(gè)關(guān)鍵字,相信很多朋友都聽(tīng)說(shuō)過(guò),甚至使用過(guò),這個(gè)關(guān)鍵字雖然字面上理解起來(lái)比較簡(jiǎn)單,但是要用好起來(lái)卻不是一件容易的事。 這篇文章將從多個(gè)方面來(lái)講解vol...

    teren 評(píng)論0 收藏0
  • 徹底搞懂JavaScript中繼承

    摘要:這正是我們想要的太棒了毫不意外的,這種繼承的方式被稱為構(gòu)造函數(shù)繼承,在中是一種關(guān)鍵的實(shí)現(xiàn)的繼承方法,相信你已經(jīng)很好的掌握了。 你應(yīng)該知道,JavaScript是一門(mén)基于原型鏈的語(yǔ)言,而我們今天的主題 -- 繼承就和原型鏈這一概念息息相關(guān)。甚至可以說(shuō),所謂的原型鏈就是一條繼承鏈。有些困惑了嗎?接著看下去吧。 一、構(gòu)造函數(shù),原型屬性與實(shí)例對(duì)象 要搞清楚如何在JavaScript中實(shí)現(xiàn)繼承,...

    _ivan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<