js易踩坑之——基本類型和引用類型(為什么要深拷貝)

在工作中樱调,有時候想操作一個對象a但是又不想改變對象a的數(shù)據(jù)祸挪,于是會使對象b=對象a屡穗,然后去操作對象b澳化。等操作完以后發(fā)現(xiàn)欠啤,咦郊艘,怎么完操作的是對象b僚祷,沒動對象a尺锚,但是對象a的數(shù)據(jù)也被改了酷师?讶凉??
為什么要這樣山孔?對象a做錯了什么要跟對象b一起承受同樣的蹂躪懂讯?—— 這還得從數(shù)據(jù)類型說起了。
為什么想起寫這個台颠,因為 我又踩了這個坑 理清基礎(chǔ)知識很重要褐望。

js數(shù)據(jù)類型

js有6中基本數(shù)據(jù)類型:String,Number串前,Boolean瘫里,Null,undefined和es6新增的symbol荡碾,一種引用數(shù)據(jù)類型:Object谨读。
需要注意的是,new出來的布爾坛吁、數(shù)字劳殖、字符串也屬于引用類型铐尚。

  • 示例1:
let num = 1;
let numNew = new Number(1);
console.log(typeof num); // number
console.log(typeof numNew); // object

let flag = true;
let flagNew = new Boolean(false);
console.log(typeof flag); // boolean
console.log(typeof flagNew); // object

let str = 'a';
let strNew = new String('b');
console.log(typeof str); // string
console.log(typeof strNew); // object

那么,基本關(guān)系搞清楚了哆姻,我們來看一下下面的例子:

  • 示例2:
let strA = 'a';
let strB = strA;
strB = 'b';
console.log(strA); // a
console.log(strB); // b

let objA = {'a':1,'b':2};
let objB = objA;
objB.a = 3;
console.log(objA); // {'a':3,'b':2}
console.log(objB); // {'a':3,'b':2}

為什么更改了strB之后strA沒變而更改了objB之后objA卻變了呢宣增?這就是傳值與傳址的區(qū)別。

因為在js中 基本類型按值引用矛缨,引用類型按地址引用爹脾。

什么是“按地址引用”?

上面的例子中箕昭,objA是指向內(nèi)存中{'a':1,'b':2}這個數(shù)據(jù)的指針灵妨,而此時let objB = objA,objB也是指向{'a':1,'b':2}這個數(shù)據(jù)(相當于新建了一個不同名的“指針”)盟广,objA和objB指向內(nèi)存中的同一個數(shù)據(jù),所以此時objB.a = 3改變的是objB指向的內(nèi)存數(shù)據(jù)的值瓮钥,而同時objA也指向此數(shù)據(jù)筋量,故而打印objA與打印objB的結(jié)果是一樣的。

注:內(nèi)存又涉及堆和棧碉熄,本文暫時不詳述桨武,感興趣的胖友可以自行了解一下

示例2:objA和objB指向同一個內(nèi)存中的數(shù)據(jù)

那么再來看一下,下面例子中應(yīng)該打印什么呢锈津?

  • 示例3:
let objA = {'a':1,'b':2};
let objB = {'a':1,'b':2};
objB.a = 3;
console.log(objA); // 呀酸?
console.log(objB); // ?
示例3:objA和objB指向內(nèi)存中的不同數(shù)據(jù)

盡管objA和objB指向的數(shù)據(jù)一樣琼梆,但是在內(nèi)存中性誉,這是兩個不同的數(shù)據(jù),所以改變objB的時候不會改變objA茎杂,objA和objB的打印為:

console.log(objA); // {'a':1,'b':2}
console.log(objB); // {'a':3,'b':2}

深拷貝和淺拷貝

對引用數(shù)據(jù)類型错览,直接用等號=賦值,實際上為復(fù)制指向某個對象的指針煌往。正如文章開頭提到的例子和示例2一樣倾哺,此時改變對象b,那對象a也發(fā)生了改變刽脖,因為他們是兩個不同名的指針指向內(nèi)存中的同一數(shù)據(jù)羞海。
而淺拷貝,是拷貝引用數(shù)據(jù)的第一層曲管,后面深層次的引用類型仍然是拷貝引用却邓,比如使用Object.assignslice院水、Object.create申尤、concat和擴展運算符等癌幕,實現(xiàn)的都是淺拷貝。
那么昧穿,怎么做到改變對象b的數(shù)據(jù)而對象a的數(shù)據(jù)不變呢勺远?
實際工作中總不能像示例3數(shù)據(jù)一開始就是固定的,所以此時时鸵,你需要進行深拷貝胶逢。將對象a的每個基本類型的數(shù)據(jù)都遍歷一遍,依次的賦值給對象b的對應(yīng)字段饰潜。避免產(chǎn)生因為地址引用帶來的問題初坠。

手動實現(xiàn)深拷貝:
這個函數(shù)只能基本滿足生產(chǎn)需求,如果參數(shù)是Dom對象彭雾、new Object ()的話,就會產(chǎn)生功能性錯誤

function deepCopy(obj1) {
    // 創(chuàng)建對應(yīng)的空對象或空數(shù)組
    let obj2 = Array.isArray(obj1) ? [] : {};
    if (obj1 && typeof obj1 === "object") {
        for (let i in obj1) {
            // 判斷是否是自身的屬性:因為for-in會遍歷原型鏈上的屬性碟刺,
            // 所以需要判斷屬性是否在原型鏈上,不是原型鏈才拷貝
            if (obj1.hasOwnProperty(i)) {
                // 如果子屬性為引用數(shù)據(jù)類型薯酝,遞歸復(fù)制
                if (obj1[i] && typeof obj1[i] === "object") {
                    obj2[i] = deepCopy(obj1[i]);
                } else {
                    // 如果是基本數(shù)據(jù)類型半沽,直接賦值
                    obj2[i] = obj1[i];
                }
            }
        }
    }
    return obj2;
}

生產(chǎn)環(huán)境中的話還是推薦用lodash_.cloneDeep,目前對深拷貝各種數(shù)據(jù)支持得最好的了吴菠。

參考文章:
1者填、誰說前端就不需要學習數(shù)據(jù)結(jié)構(gòu)了?來我們淺談一下js的數(shù)據(jù)結(jié)構(gòu)
2做葵、js 值引用和地址引用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末占哟,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子酿矢,更是在濱河造成了極大的恐慌榨乎,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瘫筐,死亡現(xiàn)場離奇詭異谬哀,居然都是意外死亡,警方通過查閱死者的電腦和手機严肪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門史煎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人驳糯,你說我怎么就攤上這事篇梭。” “怎么了酝枢?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵恬偷,是天一觀的道長。 經(jīng)常有香客問我帘睦,道長袍患,這世上最難降的妖魔是什么坦康? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮诡延,結(jié)果婚禮上滞欠,老公的妹妹穿的比我還像新娘。我一直安慰自己肆良,他們只是感情好筛璧,可當我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著惹恃,像睡著了一般夭谤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上巫糙,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天朗儒,我揣著相機與錄音,去河邊找鬼参淹。 笑死醉锄,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的承二。 我是一名探鬼主播榆鼠,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼纲爸,長吁一口氣:“原來是場噩夢啊……” “哼亥鸠!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起识啦,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤负蚊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后颓哮,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體家妆,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年冕茅,在試婚紗的時候發(fā)現(xiàn)自己被綠了伤极。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡姨伤,死狀恐怖哨坪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情乍楚,我是刑警寧澤当编,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站徒溪,受9級特大地震影響忿偷,放射性物質(zhì)發(fā)生泄漏金顿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一鲤桥、第九天 我趴在偏房一處隱蔽的房頂上張望揍拆。 院中可真熱鬧,春花似錦芜壁、人聲如沸礁凡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽顷牌。三九已至,卻和暖如春塞淹,著一層夾襖步出監(jiān)牢的瞬間窟蓝,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工饱普, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留运挫,地道東北人。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓套耕,卻偏偏與公主長得像谁帕,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子冯袍,可洞房花燭夜當晚...
    茶點故事閱讀 44,601評論 2 353

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