Javascript淺拷貝和深拷貝

前言

淺拷貝和深拷貝在前端開發(fā)中是非常重要的知識(shí)點(diǎn),有時(shí)候面試官也非常喜歡問到這點(diǎn)劣摇,相信很多人只是聽過這兩個(gè)詞,不明白他們的意思和涵義弓乙,這里將會(huì)淺顯的講解淺拷貝和深拷貝末融。總結(jié)學(xué)習(xí)的同時(shí)暇韧,希望大家也會(huì)有點(diǎn)收獲勾习。

Javascript的兩種變量類型

1、JavaScript變量的類型分為兩種: 基本類型和引用類型懈玻。

  • 基本類型是指簡(jiǎn)單的數(shù)據(jù)段巧婶,有5種類型: UndefinedNull涂乌、Boolean艺栈、NumberString
  • 引用類型是指可能有多個(gè)值構(gòu)成的對(duì)象,一般為: Object湾盒、 Array湿右、 function

2、JavaScript內(nèi)存模型圖:

image
  • 基本數(shù)據(jù)類型的特點(diǎn):直接存儲(chǔ)在棧(stack)中的數(shù)據(jù)
  • 引用數(shù)據(jù)類型的特點(diǎn):存儲(chǔ)的是該對(duì)象在棧中引用即地址历涝,真實(shí)的數(shù)據(jù)存放在堆內(nèi)存里

3诅需、基本類型是按值訪問的,不會(huì)影響到其他數(shù)據(jù)荧库,而引用類型的值是按地址訪問的堰塌,簡(jiǎn)單的賦值,實(shí)際上只是把地址復(fù)制了一遍分衫,修改任意一個(gè)值會(huì)影響到另外一個(gè)场刑。

// 1、基本數(shù)據(jù)類型蚪战,不影響其他變量
var a = '沒修改'
var b = a
a = '被修改'
b // '沒修改'

// 2牵现、引用數(shù)據(jù)類型修改,會(huì)影響其他變量
var obj1 = {a: '沒修改'}
var obj2 = obj1
obj1.a = '被修改'
console.log(obj2) // {a: '被修改'}

從上面可以看出邀桑,基本數(shù)據(jù)類型瞎疼,不影響其他變量,所以基本類型的值沒有深拷貝的概念壁畸。而對(duì)象obj1 賦值給了數(shù)組obj2,JavaScript引擎只是將obj1的地址賦值給了obj2贼急,他們指向同一個(gè)內(nèi)存地址茅茂,并沒有開辟新的棧,當(dāng)修改obj1的值太抓,obj2也被影響了空闲,這就是淺拷貝當(dāng)然很多時(shí)候我們并不希望這樣。

深拷貝和淺拷貝

深拷貝和淺拷貝的示意圖大致如下:

image

淺拷貝只復(fù)制指向某個(gè)對(duì)象的指針走敌,而不復(fù)制對(duì)象本身碴倾,新舊對(duì)象還是共享同一塊內(nèi)存。但深拷貝會(huì)另外創(chuàng)造一個(gè)一模一樣的對(duì)象掉丽,新對(duì)象跟原對(duì)象不共享內(nèi)存跌榔,修改新對(duì)象不會(huì)改到原對(duì)象。

淺拷貝机打、深拷貝和賦值的區(qū)別

賦值操作則是兩個(gè)對(duì)象一起指向一個(gè)對(duì)象矫户,無論誰改變了對(duì)象里面的內(nèi)容,都會(huì)互相影響残邀。

淺拷貝和深拷貝都是將拷貝的內(nèi)容放入新的對(duì)象中去,區(qū)別在于淺拷貝只會(huì)新增一個(gè)外層對(duì)象來放要拷貝對(duì)象的所有內(nèi)容柑蛇,所以如果要拷貝的對(duì)象里面的屬性是對(duì)象則拷貝的是對(duì)象的引用芥挣,而深拷貝則是被拷貝對(duì)象包含多少對(duì)象,深拷貝就會(huì)對(duì)應(yīng)生成多少對(duì)象來一一對(duì)應(yīng)往里裝被拷貝對(duì)象里的內(nèi)容耻台,所有的對(duì)象都是獨(dú)立全新的拷貝一份空免。

簡(jiǎn)單來說

  • 賦值操作兩個(gè)變量指向同一個(gè)對(duì)象,兩者互相影響盆耽。
  • 淺拷貝新生成一個(gè)對(duì)象蹋砚,對(duì)象里面的屬性是基本類型,拷貝的就是基本類型的值摄杂;如果屬性是內(nèi)存地址(引用類型)坝咐,拷貝的就是內(nèi)存地址。
  • 深拷貝會(huì)新生成所有對(duì)象(值對(duì)象里面層層嵌套對(duì)象)析恢,對(duì)象里面的屬性是基本類型墨坚,拷貝的就是基本類型的值;如果屬性是內(nèi)存地址(引用類型)映挂,會(huì)新生成一個(gè)對(duì)象將內(nèi)容拷貝進(jìn)去泽篮。

淺拷貝的實(shí)現(xiàn)方式

1、Object.assign()實(shí)現(xiàn)

Object.assign() 方法可以把任意多個(gè)的源對(duì)象自身的可枚舉屬性拷貝給目標(biāo)對(duì)象柑船,然后返回目標(biāo)對(duì)象帽撑。但是Object.assign()進(jìn)行的是淺拷貝,拷貝的是對(duì)象的屬性的引用鞍时,而不是對(duì)象本身亏拉。

var obj1 = { a: {a: "hello", b: 21} };

var obj2 = Object.assign({}, obj1);

obj2.a.a = "changed";

console.log(obj1.a.a); //  "changed"

如果對(duì)象里面的屬性不是對(duì)象历恐,則進(jìn)行的是深拷貝。

var obj1 = { a: 10, b: 20, c: 30 };
var obj2 = Object.assign({}, obj1);
obj2.b = 100;
console.log(obj1);
// { a: 10, b: 20, c: 30 } <-- 沒有受到影響
console.log(obj2);
// { a: 10, b: 100, c: 30 }

深拷貝的實(shí)現(xiàn)方式

1专筷、JSON.parse(JSON.stringify())實(shí)現(xiàn)

JSON.stringify把對(duì)象轉(zhuǎn)成字符串弱贼,再用JSON.parse把字符串轉(zhuǎn)成新的對(duì)象。

var obj1 = { a: { b: 10 } };
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.a.b = 20;
console.log(obj1);
// { a: { b: 10 } } <-- 沒被修改
console.log(obj2);
// { a: { b: 20 } }
console.log(obj1 === obj2);
// false
console.log(obj1.a === obj2.a);
// false

2磷蛹、遞歸拷貝

遞歸方法實(shí)現(xiàn)深度克隆原理:遍歷對(duì)象吮旅、數(shù)組直到里邊都是基本數(shù)據(jù)類型,然后再去復(fù)制味咳,就是深度拷貝庇勃。

var obj1 = {a: {name: '小紅'}, b: 2, arr:[1,2]}
var obj2 = {}       
//參數(shù):初始值,完成值
function deepClone(initalObj, finalObj) {    
  var obj = finalObj || {};    
  for (var i in initalObj) {       
    //判斷是否引用類型槽驶,object,Array 的typeof檢測(cè) 都是object
    if (typeof initalObj[i] === 'object') {
        //遞歸前责嚷,判斷是對(duì)象還是數(shù)字,初始化
      obj[i] = (initalObj[i].constructor === Array) ? [] : {};            
      //遞歸自己
      arguments.callee(initalObj[i], obj[i]);
    } else {
    //基礎(chǔ)類型值 直接復(fù)制
      obj[i] = initalObj[i];
    }
  }    
  return obj;
}

deepClone(obj1, obj2)
console.log(obj2)  //{a: {name: '小紅'}, b: 2, arr:[1,2]}

3掂铐、lodash

該函數(shù)庫也有提供_.cloneDeep用來做 Deep Copy

var _ = require('lodash');
var obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);
// false

4罕拂、Object.create()實(shí)現(xiàn)

直接使用var newObj = Object.create(oldObj),可以達(dá)到深拷貝的效果全陨。

function deepClone(initalObj, finalObj) {    
  var obj = finalObj || {};    
  for (var i in initalObj) {        
    var prop = initalObj[i]; 
    if(prop === obj) {            
      continue;
    }        
    if (typeof prop === 'object') {
      obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
    } else {
      obj[i] = prop;
    }
  }    
  return obj;
}

最后

深拷貝的話常見的是使用JSON.parse(JSON.stringify())實(shí)現(xiàn),方法比較簡(jiǎn)單方便爆班。

更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,歡迎帥哥美女前來StarH枰獭J疗小!

參考文章

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末雨涛,一起剝皮案震驚了整個(gè)濱河市枢舶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌替久,老刑警劉巖凉泄,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異侣肄,居然都是意外死亡旧困,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門稼锅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吼具,“玉大人,你說我怎么就攤上這事矩距∞趾校” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵锥债,是天一觀的道長(zhǎng)陡蝇。 經(jīng)常有香客問我痊臭,道長(zhǎng),這世上最難降的妖魔是什么登夫? 我笑而不...
    開封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任广匙,我火速辦了婚禮,結(jié)果婚禮上恼策,老公的妹妹穿的比我還像新娘鸦致。我一直安慰自己,他們只是感情好涣楷,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開白布分唾。 她就那樣靜靜地躺著,像睡著了一般狮斗。 火紅的嫁衣襯著肌膚如雪绽乔。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天碳褒,我揣著相機(jī)與錄音折砸,去河邊找鬼。 笑死骤视,一個(gè)胖子當(dāng)著我的面吹牛鞍爱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播专酗,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼盗扇!你這毒婦竟也來了祷肯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤疗隶,失蹤者是張志新(化名)和其女友劉穎佑笋,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體斑鼻,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蒋纬,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了坚弱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蜀备。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖荒叶,靈堂內(nèi)的尸體忽然破棺而出碾阁,到底是詐尸還是另有隱情,我是刑警寧澤些楣,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布脂凶,位于F島的核電站宪睹,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏蚕钦。R本人自食惡果不足惜亭病,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望嘶居。 院中可真熱鬧罪帖,春花似錦、人聲如沸食听。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽樱报。三九已至葬项,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間迹蛤,已是汗流浹背民珍。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留盗飒,地道東北人嚷量。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像逆趣,于是被迫代替她去往敵國(guó)和親蝶溶。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

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

  • 面試的時(shí)候宣渗,經(jīng)常會(huì)被問到j(luò)s的淺拷貝和深拷貝問題抖所,很多時(shí)候能夠想清楚是怎么回事,但是實(shí)在描述不出來痕囱,可能還是自己比...
    肆意咯咯咯閱讀 359評(píng)論 0 3
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,089評(píng)論 1 32
  • 人生路漫漫田轧,有你的陪伴。有你的嘮叨鞍恢,再難走的路傻粘,在長(zhǎng)的路,我也會(huì)微笑著走下去帮掉。 忘不了你的嘮叨弦悉,把我的生活照顧的無...
    任英姿閱讀 1,122評(píng)論 0 0
  • 洋洋,洋洋 初生的靈魂尚不諳世事 軀殼卻行將就木 沒有思想 或許是上天最大的恩賜 洋洋旭寿,洋洋 你要理解 有些人生下...
    馮茯苓閱讀 266評(píng)論 3 1
  • 我很貪盅称。 我不愿放棄任何一處遇見的風(fēng)景肩祥,大到名聲煊赫的建筑后室、山水,小到一棵花草混狠、一只蟲子岸霹。 從岳飛廟到雨中西湖,從...
    雨如花飛閱讀 472評(píng)論 0 5