淺拷貝和深拷貝的區(qū)別

javascript中數(shù)據(jù)存儲分為兩種類型:
1喊崖、基本類型
2、引用類型
基本類型保存在棧內(nèi)存中雇逞,引用類型的數(shù)據(jù)則保存在堆內(nèi)存中荤懂,引用數(shù)據(jù)類型的變量是一個指向 堆內(nèi)存中 實際對象的引用,存在棧中

淺拷貝 是指在創(chuàng)建新一組數(shù)據(jù)中塘砸,如果屬性是基本類型节仿,拷貝的就是基本類型的值。如果屬性是引用類型掉蔬,拷貝的就是內(nèi)存地址廊宪;

在JavaScript中存在淺拷貝的現(xiàn)象有:
Object.assign()
假如源對象的屬性值是一個對象的引用矾瘾,那么它也只指向那個引用。也就是說箭启,如果對象的屬性值為簡單類型(如string壕翩, number),通過Object.assign({},srcObj);得到的新對象為深拷貝傅寡;如果屬性值為對象或其它引用類型放妈,那對于這個對象而言其實是淺拷貝的。

var obj = {
    age: 18,
    nature: ['smart', 'good'],
    names: {
        name1: 'fx',
        name2: 'xka'
    },
    love: function () {
        console.log('fx is a great girl')
    }
}
var newObj = Object.assign({}, obj );

Array.prototype.slice() 荐操,

const fxArr = ["One", "Two", "Three"]
const fxArrs = fxArr.slice(0)
fxArrs[1] = "love";
console.log(fxArr) // ["One", "Two", "Three"]
console.log(fxArrs) // ["One", "love", "Three"]

Array.prototype.concat()

const fxArr = ["One", "Two", "Three"]
const fxArrs = fxArr.concat()
fxArrs[1] = "love";
console.log(fxArr) // ["One", "Two", "Three"]
console.log(fxArrs) // ["One", "love", "Three"]

使用拓展運算符實現(xiàn)的復(fù)制


const fxArr = ["One", "Two", "Three"]
const fxArrs = [...fxArr]
fxArrs[1] = "love";
console.log(fxArr) // ["One", "Two", "Three"]
console.log(fxArrs) // ["One", "love", "Three"]

** for ..in **

function shallowClone(obj) {
    const newObj = {};
    for(let prop in obj) {
        if(obj.hasOwnProperty(prop)){
            newObj[prop] = obj[prop];
        }
    }
    return newObj;
}

以上都存在著淺拷貝的現(xiàn)象芜抒;

深拷貝
深拷貝開辟一個新的棧,兩個對象屬性完全相同托启,但是對應(yīng)兩個不同的地址宅倒,修改一個對象的屬性,不會改變另一個對象的屬性
常見的深拷貝方式有:

_.cloneDeep() 利用方便的js庫工具 ------ lodash

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

jQuery.extend()

const $ = require('jquery');
const obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};
const obj2 = $.extend(true, {}, obj1);
console.log(obj1.b.f === obj2.b.f); // false

JSON.stringify() ----但是這種方式存在弊端驾中,會忽略undefined唉堪、symbol和函數(shù)

const obj2=JSON.parse(JSON.stringify(obj1));

const obj = {
   name: 'A',
   name1: undefined,
   name3: function() {},
   name4:  Symbol('A')
}
const obj2 = JSON.parse(JSON.stringify(obj));
console.log(obj2); // {name: "A"}

手寫循環(huán)遞歸


function deepClone(obj, hash = new WeakMap()) {
  if (obj === null) return obj; // 如果是null或者undefined我就不進(jìn)行拷貝操作
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  // 可能是對象或者普通的值  如果是函數(shù)的話是不需要深拷貝
  if (typeof obj !== "object") return obj;
  // 是對象的話就要進(jìn)行深拷貝
  if (hash.get(obj)) return hash.get(obj);
  let cloneObj = new obj.constructor();
  // 找到的是所屬類原型上的constructor,而原型上的 constructor指向的是當(dāng)前類本身
  hash.set(obj, cloneObj);
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      // 實現(xiàn)一個遞歸拷貝
      cloneObj[key] = deepClone(obj[key], hash);
    }
  }
  return cloneObj;
}

遞歸實現(xiàn)的深拷貝里面用到了 WeakMap 用來創(chuàng)建hash結(jié)構(gòu)

WeakMap結(jié)構(gòu)與Map結(jié)構(gòu)類似,也是用于生成鍵值對的集合肩民。

WeakMap與Map的區(qū)別有兩點唠亚。

首先,WeakMap只接受對象作為鍵名(null除外)持痰,不接受其他類型的值作為鍵名灶搜。

其次,WeakMap的鍵名所指向的對象工窍,不計入垃圾回收機(jī)制割卖。

// WeakMap 可以使用 set 方法添加成員
const wm1 = new WeakMap();
const key = {foo: 1};
wm1.set(key, 2);
wm1.get(key) // 2

// WeakMap 也可以接受一個數(shù)組,
// 作為構(gòu)造函數(shù)的參數(shù)
const k1 = [1, 2, 3];
const k2 = [4, 5, 6];
const wm2 = new WeakMap([[k1, 'foo'], [k2, 'bar']]);
wm2.get(k2) // "bar"

WeakMap 的語法
WeakMap 與 Map 在 API 上的區(qū)別主要是兩個患雏,
一是沒有遍歷操作(即沒有keys()鹏溯、values()和entries()方法),也沒有size屬性淹仑。
二是無法清空丙挽,即不支持clear方法。因此匀借,WeakMap只有四個方法可用:get()颜阐、set()、has()吓肋、delete()凳怨。

Map
JavaScript 的對象(Object),本質(zhì)上是鍵值對的集合(Hash 結(jié)構(gòu)),但是傳統(tǒng)上只能用字符串當(dāng)作鍵肤舞。這給它的使用帶來了很大的限制.

ES6 提供了 Map 數(shù)據(jù)結(jié)構(gòu)紫新。它類似于對象,也是鍵值對的集合李剖,但是“鍵”的范圍不限于字符串弊琴,各種類型的值(包括對象)都可以當(dāng)作鍵。也就是說杖爽,Object 結(jié)構(gòu)提供了“字符串—值”的對應(yīng),Map 結(jié)構(gòu)提供了“值—值”的對應(yīng)紫皇,是一種更完善的 Hash 結(jié)構(gòu)實現(xiàn)慰安。如果你需要“鍵值對”的數(shù)據(jù)結(jié)構(gòu),Map 比 Object 更合適聪铺。

const m = new Map();
const o = {p: 'Hello World'};

m.set(o, 'content')
m.get(o) // "content"

m.has(o) // true
m.delete(o) // true
m.has(o) // false

Map 也可以接受一個數(shù)組作為參數(shù)化焕。該數(shù)組的成員是一個個表示鍵值對的數(shù)組。

const map = new Map([
  ['name', '張三'],
  ['title', 'Author']
]);

map.size // 2
map.has('name') // true
map.get('name') // "張三"
map.has('title') // true
map.get('title') // "Author"

如果對同一個鍵多次賦值铃剔,后面的值將覆蓋前面的值撒桨。

const map = new Map();
map.set(1, 'aaa').set(1, 'bbb');
map.get(1) // "bbb"

實例的屬性和操作方法:

(1)size 屬性

(2)set(key, value)

(3)get(key)

(4)has(key)

(5)delete(key)

(6)clear()

{
 let map = new Map();
map.set('foo', 11);
map.set('bar', 22);
map.size ;// 2
map.get('foo');//t1
map.has('boo');  //true
map.delete('foo');  //true
map.clear();
map.size // 0
}

遍歷方法

Map 結(jié)構(gòu)原生提供三個遍歷器生成函數(shù)和一個遍歷方法。
keys():返回鍵名的遍歷器键兜。
values():返回鍵值的遍歷器凤类。
entries():返回所有成員的遍歷器。
forEach():遍歷 Map 的所有成員普气。
Map 結(jié)構(gòu)的默認(rèn)遍歷器接口(Symbol.iterator屬性)谜疤,就是entries方法。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末现诀,一起剝皮案震驚了整個濱河市夷磕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌仔沿,老刑警劉巖坐桩,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異封锉,居然都是意外死亡绵跷,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進(jìn)店門烘浦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來抖坪,“玉大人,你說我怎么就攤上這事闷叉〔晾” “怎么了?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵握侧,是天一觀的道長蚯瞧。 經(jīng)常有香客問我嘿期,道長,這世上最難降的妖魔是什么埋合? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任备徐,我火速辦了婚禮,結(jié)果婚禮上甚颂,老公的妹妹穿的比我還像新娘蜜猾。我一直安慰自己,他們只是感情好振诬,可當(dāng)我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布蹭睡。 她就那樣靜靜地躺著,像睡著了一般赶么。 火紅的嫁衣襯著肌膚如雪肩豁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天辫呻,我揣著相機(jī)與錄音清钥,去河邊找鬼。 笑死放闺,一個胖子當(dāng)著我的面吹牛祟昭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播怖侦,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼从橘,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了础钠?” 一聲冷哼從身側(cè)響起恰力,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎旗吁,沒想到半個月后踩萎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡很钓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年香府,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片码倦。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡企孩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出袁稽,到底是詐尸還是另有隱情勿璃,我是刑警寧澤,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站补疑,受9級特大地震影響歧沪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜莲组,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一诊胞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧锹杈,春花似錦撵孤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至市框,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間糕韧,已是汗流浹背枫振。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留萤彩,地道東北人粪滤。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像雀扶,于是被迫代替她去往敵國和親杖小。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,440評論 2 348

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