成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

沒有對(duì)象?那就復(fù)制一個(gè)吧!(科普向,實(shí)際應(yīng)用向)

amuqiao / 3260人閱讀

摘要:基本數(shù)據(jù)類型將變量和值一起放在棧內(nèi)存引用數(shù)據(jù)類型則將變量放在棧內(nèi)存而將值放在堆內(nèi)存。該怎么理解沒圖我說個(gè)假設(shè)有個(gè)變量在內(nèi)存中是這樣的棧內(nèi)存中的變量指向堆內(nèi)存中一塊內(nèi)存相當(dāng)于持有該內(nèi)存的指針,而那塊內(nèi)存中存儲(chǔ)變量的相關(guān)內(nèi)容。

趁著周五沒那么忙,抽個(gè)空整理一下最近使用比較頻繁的一個(gè)小技術(shù) 對(duì)象的深復(fù)制。
感覺啊,這個(gè)標(biāo)題和今天的節(jié)日(假裝不知道原來是情人節(jié))那么遙相呼應(yīng)。啊,沒有女朋友?沒有女朋友沒關(guān)系,復(fù)制一個(gè)啊。先走你一個(gè):console.log("GirlFriend")
同時(shí)筆者需要預(yù)個(gè)警,本篇注重實(shí)際中的應(yīng)用情況,中規(guī)中矩,不搞花里胡哨。所以主要是對(duì)數(shù)組字面量對(duì)象進(jìn)行討論,畢竟前端開發(fā)中遇到最多的對(duì)象就是這兩個(gè)了。在正式分析對(duì)象的深復(fù)制這個(gè)問題之前,筆者覺得有必要對(duì)在座的朋友科普下必要的知識(shí)。

科普區(qū)
JavaScript中數(shù)據(jù)類型分為哪幾種?

這個(gè)問題在面試中的命中率真的挺高,而且也是本篇的重要所在。了解的朋友可跳過繼續(xù)向下看,不了解的朋友請跟著我慢慢理解。
JavaScript中數(shù)據(jù)類型分為基本數(shù)據(jù)類型引用數(shù)據(jù)類型 (當(dāng)然還有別的叫法,只是筆者認(rèn)為這種叫法更科學(xué))。

基本數(shù)據(jù)類型: null, undefined, int, string, boolean

引用數(shù)據(jù)類型: {"a":"b"}(字面量對(duì)象), Array, Map, Set, Symbol 等等...其實(shí)就是基本數(shù)據(jù)類型以外的類型

而且,不同的數(shù)據(jù)類型在內(nèi)存中的存儲(chǔ)方式也是不同的:

基本數(shù)據(jù)類型在內(nèi)存中的存儲(chǔ)方式

我們都知道,JavaScript中的內(nèi)存分為棧內(nèi)存堆內(nèi)存(不知道?請點(diǎn)擊)。基本數(shù)據(jù)類型將變量和值一起放在棧內(nèi)存;引用數(shù)據(jù)類型則將變量放在棧內(nèi)存而將值放在堆內(nèi)存。先來講基本數(shù)據(jù)類型
基本數(shù)據(jù)類型在JavaScript編程中用得極為廣泛,比如:

let a = 1;
let b = "name";
let c = true;
let d = null;
let e = undefined;

這些都屬于基本數(shù)據(jù)類型,都存儲(chǔ)在棧內(nèi)存中;如以下形式:

棧內(nèi)存中的變量數(shù)據(jù)有個(gè)好處是如果需要獲取某個(gè)變量值的copy值很方便,直接通過 = 操作即可,不需要考慮額外的問題。比如:let f = a; 這個(gè)操作意在拷貝一份 a 這個(gè)變量,此時(shí)棧內(nèi)存中就變成這樣了:

多出一個(gè)變量 f,即使說是從 a 復(fù)制而來的,結(jié)果卻和 a 沒有任何關(guān)系。用代碼驗(yàn)證一下:

let a = 1;
let f = a;

//此時(shí)改變a的值
a = 2;

console.log(`a 是${a}`);
console.log(`f 是${f}`);

運(yùn)行結(jié)果:

引用數(shù)據(jù)類型在內(nèi)存中的存儲(chǔ)方式

上面說到:引用數(shù)據(jù)類型則將變量放在棧內(nèi)存而將值放在堆內(nèi)存。該怎么理解?沒圖我說個(gè)jb?
假設(shè)有個(gè)變量person:

let person={
    "name":"Mario"
}

在內(nèi)存中是這樣的

棧內(nèi)存中的變量 person 指向堆內(nèi)存中一塊內(nèi)存(相當(dāng)于持有該內(nèi)存的指針),而那塊內(nèi)存中存儲(chǔ) person 變量的相關(guān)內(nèi)容。
因此可以看出引用數(shù)據(jù)類型的復(fù)制并沒有基本數(shù)據(jù)類型來得方便。即便如此,我們還是來證實(shí)下這個(gè)想法:

let person={
    "name":"Mario"
}

let person_copy = person;

//修改person中的內(nèi)容
person["name"]="JavaScript";

console.log(`person: ${person["name"]}`);
console.log(`person_copy: ${person_copy["name"]}`);

運(yùn)行結(jié)果:

可以看出當(dāng)我們復(fù)制好一份 person_copy ,并對(duì) person 進(jìn)行了一次修改。結(jié)果兩個(gè)變量同時(shí)變化。為什么?
因?yàn)楫?dāng)程序進(jìn)行到let person_copy = person;這里的時(shí)候,并不是直接把 person 的內(nèi)容賦值給變量 person_copy,而是把 person 的指針賦值給了變量 person_copy。

所以說變量 person 和 person_copy 都持有了該內(nèi)存塊的指針,因此不管哪個(gè)變量修改了內(nèi)存中的內(nèi)容,另一個(gè)變量對(duì)應(yīng)的值也會(huì)變化。最終我們可以確定:如果想復(fù)制一個(gè)引用類型的數(shù)據(jù),就是要將該內(nèi)存塊中的內(nèi)容復(fù)制進(jìn)另一個(gè)內(nèi)存塊中并把新的指針賦值給新變量。

大概內(nèi)容已經(jīng)科普完了,接下來就開始本文的重點(diǎn)內(nèi)容

對(duì)象的(深)復(fù)制

在開發(fā)過程中,如果某條數(shù)據(jù)(尤其是從后臺(tái)請求回來的數(shù)據(jù))使用頻率很高而且用途復(fù)雜,那么就不得不為它進(jìn)行一次復(fù)制以備不時(shí)之需。針對(duì)使用頻率較高的兩個(gè)對(duì)象數(shù)組字面量對(duì)象,我們開始逐一討論。

數(shù)組的復(fù)制

數(shù)組在實(shí)際開發(fā)中,元素主要分為基本數(shù)據(jù)類型字面量對(duì)象(不排除還有別的類型數(shù)據(jù),只是筆者沒遇到過,所以只針對(duì)普遍的情況)。
針對(duì)元素是基本數(shù)據(jù)類型的數(shù)組的復(fù)制操作,筆者提供4種方法:

ES6的對(duì)象擴(kuò)展運(yùn)算符 [...]

let origin = [1, 2, 3, 4, 5];
let another = [...origin];

//向原數(shù)組中添加一個(gè)元素
origin.push(6);
console.log(`another元素: ${another}`);

運(yùn)算結(jié)果:

slice

let origin = [1, 2, 3, 4, 5];
let another = origin.slice();

//向原數(shù)組中添加一個(gè)元素
origin.push(6);
console.log(`another元素: ${another}`);

運(yùn)行結(jié)果:

concat

let origin = [1, 2, 3, 4, 5];

//相當(dāng)于向origin中拼接一個(gè)空數(shù)組
let another = origin.concat([]);

//向原數(shù)組中添加一個(gè)元素
origin.push(6);
console.log(`another元素: ${another}`);

運(yùn)行結(jié)果:

JSON.stringify

這個(gè)方法可行但是幾乎沒人這么用。原理是將數(shù)組轉(zhuǎn)為字符串再轉(zhuǎn)回?cái)?shù)組類型。

let origin = [1, 2, 3, 4, 5];
let another = JSON.parse(JSON.stringify(origin));

//向原數(shù)組中添加一個(gè)元素
origin.push(6);
console.log(`another元素: ${another}`);

運(yùn)行結(jié)果:

其中筆者覺得第一和第二個(gè)方法比較好用。不過如果數(shù)組中的元素是字面量對(duì)象的話,請繼續(xù)向下看。

字面量對(duì)象的深復(fù)制

實(shí)際開發(fā)中,所謂字面量對(duì)象可以人為是一段json數(shù)據(jù)。json的重要性不用說,那么相當(dāng)重要,前后端交互的核心。
先給出一段json:

{
    "name": "Mario",
    "age": 26,
    "isCoder": true,
    "homeWebPage": null,
    "fullStackSkills": undefined,
    "hobbies": ["LoL", "Travel", "Coding"],
    "phone": {
        "home": 123321,
        "office": 456654
    }
}

首先分析這段json中的數(shù)據(jù),不管是基本數(shù)據(jù)類型還是引用數(shù)據(jù)類型都有了,所以想要復(fù)制這個(gè)json對(duì)象,我們需要針對(duì)不同的數(shù)據(jù)做不同的處理。根據(jù)科普的知識(shí)我們已經(jīng)知道,復(fù)制基本數(shù)據(jù)類型可以直接賦值,對(duì)于引用數(shù)據(jù)類型則不行,而且主要使用到的數(shù)組和字面量對(duì)象(這里也可以認(rèn)為是json)這兩個(gè)類型數(shù)據(jù)的復(fù)制方法都不同。因此我們首先要判斷某一個(gè)數(shù)值是否是對(duì)象:

//判斷item是否為"object";該方法主要是為了區(qū)分參數(shù)是基本類型還是引用類型
function isObject(item) {
    return (item === null || item === undefined) ? false : (typeof item === "object");
}

其次,我們可以看到origin是一段json,orgin中的phone字段對(duì)應(yīng)的值也是一段json,所以要想整個(gè)復(fù)制這個(gè)對(duì)象難免要用到遞歸,一層一層嵌套進(jìn)行。奉上核心代碼:

/**
 * 
 * @param {字面量對(duì)象} origin 
 * @param {origin的鏡像對(duì)象} mirror
 */
function deepClone(origin, mirror) {
    //獲取該字面量對(duì)象的所有的key
    let keys = Object.keys(origin);
    //遍歷所有的key已保證復(fù)制的完整
    keys.forEach(key => {
        let value = origin[key];
        if (isObject(value)) {   //判斷是否為對(duì)象,如果是則需要額外處理;如果不是則直接復(fù)制
            if (Array.isArray(value)) { //判斷是否為數(shù)組,如果是則需要復(fù)制該數(shù)組并存入mirror;如果不是則進(jìn)行遞歸調(diào)用
                let copy = value.slice();
                mirror[key] = copy;
            } else {
                //初始化本次字面量對(duì)象的鏡像對(duì)象
                let obj = {};
                mirror[key] = obj;
                //引用傳值
                //遞歸調(diào)用
                deepClone(value, obj);
            }
        } else {
            mirror[key] = value;
        }
    });
}

通過測試,

//Test
let mirror = {};
deepClone(origin, mirror);

//向原對(duì)象中的hobbies中增加一項(xiàng)
origin["hobbies"].push("Eat");
console.log(mirror);

運(yùn)行結(jié)果:

證明方法有效。
當(dāng)然針對(duì)json數(shù)據(jù)的復(fù)制,也可以只用JSON.parse(JSON.stringify(origin))實(shí)現(xiàn),具體效率怎么樣,筆者也沒有進(jìn)行測試。所以這塊有待驗(yàn)證。因?yàn)樵撐恼伦⒅貙?shí)際開發(fā)中的應(yīng)用,所以例子沒有用到復(fù)雜的對(duì)象(例如:Set, Symbol 等等...)。所以如果有這個(gè)疑問的朋友也不用糾結(jié)了。

寫得差不多了,能想到了就這些了...收拾收拾準(zhǔn)備跑路了

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/108309.html

相關(guān)文章

  • 我對(duì)分布式一致性協(xié)議的學(xué)習(xí)心得 - CAP、BASE、NWR

    摘要:當(dāng)發(fā)生網(wǎng)絡(luò)分區(qū)時(shí),你將面臨兩個(gè)選擇如果堅(jiān)持保持各節(jié)點(diǎn)之間的數(shù)據(jù)一致性選擇,你需要等待網(wǎng)絡(luò)分區(qū)恢復(fù)后,將數(shù)據(jù)復(fù)制完成,才可以向外部提供服務(wù)。期間發(fā)生網(wǎng)絡(luò)分區(qū)將不能對(duì)外提供服務(wù),因?yàn)樗WC不了數(shù)據(jù)一致性。則強(qiáng)調(diào)是高可用,對(duì)數(shù)據(jù)一致性要求更低。這篇文章著重點(diǎn)不在于科普,畢竟關(guān)于CAP、BASE的理論的文章,網(wǎng)上很多。所以本文科普篇幅盡量?。ㄖ话拍蠲枋觯V饕獜膸讉€(gè)側(cè)面的問題來描述CAP,進(jìn)而描...

    Tecode 評(píng)論0 收藏0
  • JWT(Json Web Token) 科普

    摘要:部分是對(duì)前兩部分的簽名,防止數(shù)據(jù)篡改。也就是說,一旦簽發(fā)了,在到期之前就會(huì)始終有效,除非服務(wù)器部署額外的邏輯。為了減少盜用,的有效期應(yīng)該設(shè)置得比較短。為了減少盜用,不應(yīng)該使用協(xié)議明碼傳輸,要使用協(xié)議傳輸。 JSON Web Token(縮寫 JWT)是目前最流行的跨域認(rèn)證解決方案,本文介紹它的原理和用法。 showImg(https://www.wangbase.com/blogimg...

    SKYZACK 評(píng)論0 收藏0
  • 科普丨到底什么是Content Delivery Network云分發(fā)網(wǎng)絡(luò)CDN?

    摘要:而,是部分內(nèi)容的緩存,智能程度更高。用戶向緩存服務(wù)器發(fā)起請求,緩存服務(wù)器響應(yīng)用戶請求,將用戶所需內(nèi)容傳送到用戶終端。內(nèi)容進(jìn)行分發(fā)后,源服務(wù)器的被隱藏,受到攻擊的概率會(huì)大幅下降。由一個(gè)核心云計(jì)算中心,對(duì)所有終端節(jié)點(diǎn)提供服務(wù)。如今這個(gè)移動(dòng)互聯(lián)網(wǎng)時(shí)代,越來越多的人使用手機(jī)觀看視頻,豐富自己的娛樂生活??墒牵蠹以谧穭〉臅r(shí)候,有沒有想過一個(gè)問題——為什么有時(shí)候明明自己的網(wǎng)速很快,但觀看視頻時(shí),仍然卡...

    Tecode 評(píng)論0 收藏0
  • GraphQL 科普 前端

    摘要:樣例前端傳入字段和結(jié)構(gòu)。后臺(tái)按照前端的需求返回?cái)?shù)據(jù)。則將前后臺(tái)通信直接分為兩大類和。顧名思義,是默認(rèn)的操作符,代表查詢,是不會(huì)給服務(wù)端帶來副作用的請求。文檔文檔部分文檔就是前端向后臺(tái)描述所需的字段。降低前后端溝通成本。 簡介 showImg(https://segmentfault.com/img/bVbmKX5?w=150&h=150); GraphQL是基于「類型系統(tǒng)」來執(zhí)行查詢的...

    Bmob 評(píng)論0 收藏0
  • 科普跨站平臺(tái) XSS shell 使用方法

    摘要:例如這說明在應(yīng)用程序的消息中響應(yīng)。這意味著應(yīng)用程序從中提取信息對(duì)其進(jìn)行處理,并顯示給用戶。配置使用服務(wù)器。根據(jù)請求,服務(wù)器建立一個(gè)通道與受害人進(jìn)行交互。受害者受害者部分顯示了受害者的名單。 理解xss shell是什么之前,讓我們一起回顧一下一些基本的xss(跨站腳本),xss是最常見的一個(gè)漏洞,存在于今天許多的web應(yīng)用程序。xss是攻擊者試圖通過web應(yīng)用程序執(zhí)行惡意腳本的技術(shù),攻...

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

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

0條評(píng)論

amuqiao

|高級(jí)講師

TA的文章

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