摘要:將他們放在堆中是為了不影響棧的效率。所以簡(jiǎn)單數(shù)據(jù)類型的值直接存放在棧中??梢詫?duì)比上面那張圖默認(rèn)是調(diào)用方法的依,于是等于空字符串??兆址袊?guó)標(biāo)準(zhǔn)時(shí)間方法返回對(duì)象的原始值,可能是字符串?dāng)?shù)值或值等,看具體的對(duì)象。,需要兩個(gè)操作數(shù)同時(shí)轉(zhuǎn)為。
你是否在面試中遇到過各種奇葩和比較細(xì)節(jié)的問題?
[]==[] //false []==![] //true {}==!{} //false {}==![] //VM1896:1 Uncaught SyntaxError: Unexpected token == ![]=={} //false []==!{} //true undefined==null //true
看了這種題目,是不是想抽面試官幾耳光呢?哈哈,是不是看了之后一臉懵逼,兩臉茫然呢?心想這什么玩意
其實(shí)這些都是紙老虎,知道原理和轉(zhuǎn)換規(guī)則,理解明白這些很容易的,炒雞容易的,真的一點(diǎn)都不難,我們要打到一切紙老虎,不信?
我們就從[] == []和[] == ![]例子切入分析一下為什么輸出的結(jié)果是true而不是其它的呢?
[]==[]為什么是false?有點(diǎn)js基礎(chǔ)應(yīng)該知道對(duì)象是引用類型,就會(huì)一眼看出來[] == []會(huì)輸出false,因?yàn)樽筮叺腫]和右邊的[]看起來長(zhǎng)的一樣,但是他們引用的地址并不同,這個(gè)是同一類型的比較,所以相對(duì)沒那么麻煩,暫時(shí)不理解[] == []為false的童鞋這里就不細(xì)說,想要弄清楚可以通過這篇文章來了解JavaScript的內(nèi)存空間詳解.
前端基礎(chǔ)進(jìn)階(一):內(nèi)存空間詳細(xì)圖解
變量對(duì)象與堆內(nèi)存
簡(jiǎn)單類型都放在棧(stack)里 對(duì)象類型都放在堆(heap)里 var a = 20; var b = "abc"; var c = true; var d = { m: 20 }//地址假設(shè)為0x0012ff7c var e = { m: 20 }//重新開辟一段內(nèi)存空間假設(shè)為0x0012ff8f console.log(e==d);//false
首先,我們來看一下代碼:
function Person(id,name,age){ this.id = id; this.name = name; this.age = age; } var num = 10; var bol = true; var str = "abc"; var obj = new Object(); var arr = ["a","b","c"]; var person = new Person(100,"笨蛋的座右銘",25);
然后我們來看一下內(nèi)存分析圖:
`變量num,bol,str為基本數(shù)據(jù)類型,它們的值,直接存放在棧中,obj,person,arr為復(fù)合數(shù)據(jù)類型,他們的引用變量存儲(chǔ)在棧中,指向于存儲(chǔ)在堆中的實(shí)際對(duì)象。
由上圖可知,我們無法直接操縱堆中的數(shù)據(jù),也就是說我們無法直接操縱對(duì)象,但我們可以通過棧中對(duì)對(duì)象的引用來操作對(duì)象,就像我們通過遙控機(jī)操作電視機(jī)一樣,區(qū)別在于這個(gè)電視機(jī)本身并沒有控制按鈕。
`
`記住一句話:能量是守衡的,無非是時(shí)間換空間,空間換時(shí)間的問題
堆比棧大,棧比堆的運(yùn)算速度快,對(duì)象是一個(gè)復(fù)雜的結(jié)構(gòu),并且可以自由擴(kuò)展,如:數(shù)組可以無限擴(kuò)充,對(duì)象可以自由添加屬性。將他們放在堆中是為了不影響棧的效率。而是通過引用的方式查找到堆中的實(shí)際對(duì)象再進(jìn)行操作。相對(duì)于簡(jiǎn)單數(shù)據(jù)類型而言,簡(jiǎn)單數(shù)據(jù)類型就比較穩(wěn)定,并且它只占據(jù)很小的內(nèi)存。不將簡(jiǎn)單數(shù)據(jù)類型放在堆是因?yàn)橥ㄟ^引用到堆中查找實(shí)際對(duì)象是要花費(fèi)時(shí)間的,而這個(gè)綜合成本遠(yuǎn)大于直接從棧中取得實(shí)際值的成本。所以簡(jiǎn)單數(shù)據(jù)類型的值直接存放在棧中。`
搬運(yùn)文章:理解js內(nèi)存分配
首先第一步:你要明白ECMAScript規(guī)范里面==的真正含義
GetValue 會(huì)獲取一個(gè)子表達(dá)式的值(消除掉左值引用),在表達(dá)式 [] == ![] 中,[] 的結(jié)果就是一個(gè)空數(shù)組的引用(上文已經(jīng)介紹到數(shù)組是引用類型),而 ![] 就有意思了,它會(huì)按照 11.4.9 和 9.2 節(jié)的要求得到 false。
首先我們了解一下運(yùn)算符的優(yōu)先級(jí):
剛看到這里是不是就咬牙切齒了,好戲還在后頭呢,哈哈
!取反運(yùn)算符的優(yōu)先級(jí)會(huì)高于==,所以我們先看看!在ECAMScript是怎么定義的?
所以![]最后會(huì)是一個(gè)Boolean類型的值(這點(diǎn)很關(guān)鍵,涉及到下面的匹配選擇).
兩者比較的行為在 11.9.3 節(jié)里,所以翻到 11.9.3:
在這段算法里,[]是Object,![]是Boolean,兩者的類型不同,y是Boolean類型,由此可知[] == ![]匹配的是條件 8,所以會(huì)遞歸地調(diào)用[] == ToNumber(Boolean)進(jìn)行比較。
[]空數(shù)組轉(zhuǎn)化成Boolean,那么這個(gè)結(jié)果到底是true還是false呢,這個(gè)當(dāng)然不是你說了算,也不是我說了算,ECMAScript定義的規(guī)范說了算:我們來看看規(guī)范:
[]是一個(gè)對(duì)象,所以對(duì)應(yīng)轉(zhuǎn)換成Boolean對(duì)象的值為true;那么![]對(duì)應(yīng)的Boolean值就是false
進(jìn)而就成了比較[] == ToNumber(false)了
再來看看ECMAScipt規(guī)范中對(duì)于Number的轉(zhuǎn)換
由此可以得出此時(shí)的比較成了[]==0;
在此處因?yàn)?[] 是對(duì)象,0是數(shù)字Number,比較過程走分支 10(若Type(x)為Object且Type(y)為String或Number, 返回比較ToPrimitive(x) == y的結(jié)果。),可以對(duì)比上面那張圖.
ToPrimitive 默認(rèn)是調(diào)用 toString 方法的(依 8.2.8),于是 ToPrimitice([]) 等于空字符串。
再來看看ECMAScript標(biāo)準(zhǔn)怎么定義ToPrimitice方法的:
是不是看了這個(gè)定義,還是一臉懵逼,ToPrimitive這尼瑪什么玩意啊?這不是等于沒說嗎?
再來看看火狐MDN上面文檔的介紹:
JS::ToPrimitive
查了一下資料,上面要說的可以概括成:
ToPrimitive(obj,preferredType) JS引擎內(nèi)部轉(zhuǎn)換為原始值ToPrimitive(obj,preferredType)函數(shù)接受兩個(gè)參數(shù),第一個(gè)obj為被轉(zhuǎn)換的對(duì)象,第二個(gè) preferredType為希望轉(zhuǎn)換成的類型(默認(rèn)為空,接受的值為Number或String) 在執(zhí)行ToPrimitive(obj,preferredType)時(shí)如果第二個(gè)參數(shù)為空并且obj為Date的事例時(shí),此時(shí)preferredType會(huì) 被設(shè)置為String,其他情況下preferredType都會(huì)被設(shè)置為Number如果preferredType為Number,ToPrimitive執(zhí) 行過程如 下: 1. 如果obj為原始值,直接返回; 2. 否則調(diào)用 obj.valueOf(),如果執(zhí)行結(jié)果是原始值,返回之; 3. 否則調(diào)用 obj.toString(),如果執(zhí)行結(jié)果是原始值,返回之; 4. 否則拋異常。 如果preferredType為String,將上面的第2步和第3步調(diào)換,即: 1. 如果obj為原始值,直接返回; 2. 否則調(diào)用 obj.toString(),如果執(zhí)行結(jié)果是原始值,返回之; 3. 否則調(diào)用 obj.valueOf(),如果執(zhí)行結(jié)果是原始值,返回之; 4. 否則拋異常。
首先我們要明白obj.valueOf()和 obj.toString()還有原始值分別是什么意思,這是弄懂上面描述的前提之一:
toString用來返回對(duì)象的字符串表示。
var obj = {}; console.log(obj.toString());//[object Object] var arr2 = []; console.log(arr2.toString());//""空字符串 var date = new Date(); console.log(date.toString());//Sun Feb 28 2016 13:40:36 GMT+0800 (中國(guó)標(biāo)準(zhǔn)時(shí)間)
valueOf方法返回對(duì)象的原始值,可能是字符串、數(shù)值或bool值等,看具體的對(duì)象。
var obj = { name: "obj" }; console.log(obj.valueOf());//Object {name: "obj"} var arr1 = [1]; console.log(arr1.valueOf());//[1] var date = new Date(); console.log(date.valueOf());//1456638436303 如代碼所示,三個(gè)不同的對(duì)象實(shí)例調(diào)用valueOf返回不同的數(shù)據(jù)
**原始值指的是["Null","Undefined","String","Boolean","Number"]五種基本數(shù)據(jù)類型之一(我猜的,查了一下
確實(shí)是這樣的)**
弄清楚這些以后,舉個(gè)簡(jiǎn)單的例子:
var a={}; ToPrimitive(a) 分析:a是對(duì)象類型但不是Date實(shí)例對(duì)象,所以preferredType默認(rèn)是Number,先調(diào)用a.valueOf()不是原始值,繼續(xù)來調(diào) 用a.toString()得到string字符串,此時(shí)為原始值,返回之.所以最后ToPrimitive(a)得到就是"[object Object]".
如果覺得描述還不好明白,一大堆描述晦澀又難懂,我們用代碼說話:
const toPrimitive = (obj, preferredType="Number") => { let Utils = { typeOf: function(obj) { return Object.prototype.toString.call(obj).slice(8, -1); }, isPrimitive: function(obj) { let types = ["Null", "String", "Boolean", "Undefined", "Number"]; return types.indexOf(this.typeOf(obj)) !== -1; } }; if (Utils.isPrimitive(obj)) { return obj; } preferredType = (preferredType === "String" || Utils.typeOf(obj) === "Date") ? "String" : "Number"; if (preferredType === "Number") { if (Utils.isPrimitive(obj.valueOf())) { return obj.valueOf() }; if (Utils.isPrimitive(obj.toString())) { return obj.toString() }; } else { if (Utils.isPrimitive(obj.toString())) { return obj.toString() }; if (Utils.isPrimitive(obj.valueOf())) { return obj.valueOf() }; } } var a={}; ToPrimitive(a);//"[object Object]",與上面文字分析的一致
分析了這么多,剛才分析到哪里了,好像到了比較ToPrimitive([]) == 0現(xiàn)在我們知道ToPrimitive([])="",也就是空字符串;
那么最后就變成了""==0這種狀態(tài),繼續(xù)看和比較這張圖
發(fā)現(xiàn)typeof("")為string,0為number,發(fā)現(xiàn)第5條滿足規(guī)則,最后就成了toNumber("")==0的比較了,根據(jù)toNumber的轉(zhuǎn)換規(guī)則:
所以toNumber("")=0,最后也就成了0 == 0的問題,于是[]==![]最后成了0 == 0的問題,答案顯而易見為true,一波三折
最后總結(jié)一下==運(yùn)算規(guī)則的圖形化表示
前面說得很亂,根據(jù)我們得到的最終的圖3,我們總結(jié)一下==運(yùn)算的規(guī)則: 1. undefined == null,結(jié)果是true。且它倆與所有其他值比較的結(jié)果都是false。 2. String == Boolean,需要兩個(gè)操作數(shù)同時(shí)轉(zhuǎn)為Number。 3. String/Boolean == Number,需要String/Boolean轉(zhuǎn)為Number。 4. Object == Primitive,需要Object轉(zhuǎn)為Primitive(具體通過valueOf和toString方法)。 瞧見沒有,一共只有4條規(guī)則!是不是很清晰、很簡(jiǎn)單。主要參考文章和文獻(xiàn)
ECMAScript5.1規(guī)范中文版
通過一張簡(jiǎn)單的圖,讓你徹底地、永久地搞懂JS的==運(yùn)算
JavaScript中加號(hào)運(yùn)算符的類型轉(zhuǎn)換優(yōu)先級(jí)是什么?
喜歡我總結(jié)的文章對(duì)你有幫助有收獲的話麻煩點(diǎn)個(gè)star
我的github博客地址,總結(jié)的第一篇,不好之處和借鑒不得到之處還望見諒,您的支持就是我的動(dòng)力!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/81645.html
摘要:還記得剛開始學(xué)習(xí)的時(shí)候,內(nèi)存管理前端掘金作為一門高級(jí)語(yǔ)言,并不像低級(jí)語(yǔ)言那樣擁有對(duì)內(nèi)存的完全掌控。第三方庫(kù)的行代碼內(nèi)實(shí)現(xiàn)一個(gè)前端掘金前言本文會(huì)教你如何在行代碼內(nèi),不依賴任何第三方的庫(kù),用純實(shí)現(xiàn)一個(gè)。 (譯) 如何使用 JavaScript 構(gòu)建響應(yīng)式引擎 —— Part 1:可觀察的對(duì)象 - 掘金原文地址:How to build a reactive engine in JavaSc...
摘要:還記得剛開始學(xué)習(xí)的時(shí)候,內(nèi)存管理前端掘金作為一門高級(jí)語(yǔ)言,并不像低級(jí)語(yǔ)言那樣擁有對(duì)內(nèi)存的完全掌控。第三方庫(kù)的行代碼內(nèi)實(shí)現(xiàn)一個(gè)前端掘金前言本文會(huì)教你如何在行代碼內(nèi),不依賴任何第三方的庫(kù),用純實(shí)現(xiàn)一個(gè)。 (譯) 如何使用 JavaScript 構(gòu)建響應(yīng)式引擎 —— Part 1:可觀察的對(duì)象 - 掘金原文地址:How to build a reactive engine in JavaSc...
摘要:中抽象相等比較算法大致介紹一下的數(shù)據(jù)類型的數(shù)據(jù)類型分為種如果再加上數(shù)據(jù)類型,一共種與的區(qū)別描述一個(gè)空值空的對(duì)象引用即空指針,被當(dāng)做一個(gè)對(duì)象,輸出為算是一個(gè)吧,輸出為。運(yùn)算符把其值參數(shù)轉(zhuǎn)換為非類型對(duì)象。 Javascript中抽象相等比較算法 undefined==null //true []==[] //false []==![] //true {}==!{} //false ![]=...
摘要:這樣優(yōu)化后我們最多進(jìn)行次判斷即可,大大提高了代碼的性能。表達(dá)式的值具有離散性, 個(gè)人博客,點(diǎn)擊查看目錄,喜歡可以關(guān)注一下. 1.從[]==![]為true來剖析JavaScript各種蛋疼的類型轉(zhuǎn)換 2.吹毛求疵的追求優(yōu)雅高性能JavaScript 李小龍說過:天下武功,無堅(jiān)不摧,唯快不破.(真的說過嗎?)我想說的是:世間網(wǎng)站,完美體驗(yàn),唯快不破.(這個(gè)我承認(rèn)我說過.) showImg...
摘要:昨天在微博上看到一篇文章,也寫數(shù)組去重,主要推崇的方法是將利用數(shù)組元素當(dāng)作對(duì)象來去重。我在微博轉(zhuǎn)發(fā)了用對(duì)象去重不是個(gè)好辦法然后作者問什么才是推薦的方法。實(shí)例對(duì)象實(shí)例對(duì)象主要指通過構(gòu)造函數(shù)類生成的對(duì)象。 本文同時(shí)發(fā)布于個(gè)人博客https://www.toobug.net/articl... JavaScript的數(shù)組去重是一個(gè)老生常談的話題了。隨便搜一搜就能找到非常多不同版本的解法。 昨...
閱讀 736·2023-04-26 02:08
閱讀 2776·2021-11-18 10:02
閱讀 3542·2021-11-11 16:55
閱讀 2408·2021-08-17 10:13
閱讀 2960·2019-08-30 15:53
閱讀 737·2019-08-30 15:44
閱讀 2615·2019-08-30 11:10
閱讀 1817·2019-08-29 16:57