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

資訊專欄INFORMATION COLUMN

從[]==![]為true來剖析JavaScript各種蛋疼的類型轉(zhuǎn)換

Jeff / 1329人閱讀

摘要:將他們放在堆中是為了不影響棧的效率。所以簡(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
那為什么引用值要放在堆中,而原始值要放在棧中,不都是在內(nèi)存中嗎,為什么不放在一起呢?那接下來,讓我們來探索問題的答案!(扯遠(yuǎn)了)

首先,我們來看一下代碼:

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ī)本身并沒有控制按鈕。
`

現(xiàn)在讓我們來回答為什么引用值要放在堆中,而原始值要放在棧中的問題:

`記住一句話:能量是守衡的,無非是時(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)存分配

知道的大神當(dāng)然可以飄過,這里主要給計(jì)算機(jī)基礎(chǔ)薄弱的童鞋補(bǔ)一下課.

[]==![]為什么是true?

首先第一步:你要明白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

相關(guān)文章

  • js技術(shù) - 收藏集 - 掘金

    摘要:還記得剛開始學(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...

    Guakin_Huang 評(píng)論0 收藏0
  • js技術(shù) - 收藏集 - 掘金

    摘要:還記得剛開始學(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...

    zhou_you 評(píng)論0 收藏0
  • js中抽象相等==

    摘要:中抽象相等比較算法大致介紹一下的數(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 ![]=...

    hzx 評(píng)論0 收藏0
  • 吹毛求疵的追求優(yōu)雅高性能JavaScript

    摘要:這樣優(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...

    saucxs 評(píng)論0 收藏0
  • 也談JavaScript數(shù)組去重

    摘要:昨天在微博上看到一篇文章,也寫數(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è)老生常談的話題了。隨便搜一搜就能找到非常多不同版本的解法。 昨...

    崔曉明 評(píng)論0 收藏0

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

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<