您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“分析JavaScript淺拷貝和深拷貝”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“分析JavaScript淺拷貝和深拷貝”吧!
對象是引用類型,如果直接賦值給另外一個對象,那么只是賦值一個引用,實際上兩個變量指向的同一個數(shù)據(jù)對象,如果其中一個對象的屬性變更,那么另外一個也會變更。
示例1,簡單示例:
let human1 = { id: 1, name: "happy" }; human2 = human1; // 這里就是直接賦值 console.log(human1); // {id: 1, name: 'happy'} console.log(human2); // {id: 1, name: 'happy'} // 更改human1的名稱,human2的也會更改 human1.name = "life"; console.log(human1); // {id: 1, name: 'life'} console.log(human2); // {id: 1, name: 'life'}
示例2,對象作為參數(shù)傳遞也是傳遞引用:
let human1 = { id: 1, name: "happy" }; console.log(human1); // {id: 1, name: 'happy'} function foo(human) { // 這里更改了human對象的名稱 human.name = "life"; } foo(human1); // 傳遞對象是傳遞引用 console.log(human1); // {id: 1, name: 'life'}
淺拷貝只是復(fù)制了對象的第一層,如果第一層的屬性值是對象,那么該屬性也只是復(fù)制了一個引用。
let object1 = { a: 1, b: { // b是對象 b1: 2 } }; object2 = Object.assign({}, object1); // 這里就是淺拷貝,其中的b對象只復(fù)制了引用 // a是常規(guī)類型,不會互相影響 object1.a = 10; console.log(object1.a); // 10 console.log(object2.a); // 1 // b是對象,會互相影響 object1.b.b1 = 20; console.log(object1.b.b1); // 20 console.log(object2.b.b1); // 20
如果要實現(xiàn)完整的復(fù)制,就要使用深拷貝。
森拷貝就是不光是一層要復(fù)制,里面的層如果是對象也要進(jìn)行復(fù)制。
如果對象可以確認(rèn)是JSON
對象,那么可以用JSON
對象的方式。
沿用上面的例子:
let object1 = { a: 1, b: { // b是對象 b1: 2 } }; object2 = JSON.parse(JSON.stringify(object1)); // 深拷貝 // a是常規(guī)類型,不會互相影響 object1.a = 10; console.log(object1.a); // 10 console.log(object2.a); // 1 // b是對象,也不會互相影響 object1.b.b1 = 20; console.log(object1.b.b1); // 20 console.log(object2.b.b1); // 2
這邊深拷貝的原理其實就是先把對象轉(zhuǎn)成json
字符串,然后再轉(zhuǎn)成json
對象,中間轉(zhuǎn)成json
字符串后就和原來的對象沒有關(guān)系了。
這方法的優(yōu)點:實現(xiàn)非常簡單。
缺點:
如果有屬性值是函數(shù)的話,那么無法進(jìn)行復(fù)制,數(shù)據(jù)會丟失。
另外原型對象無法進(jìn)行復(fù)制。
所以這種方式只適合對象確認(rèn)是一個純粹的json
數(shù)據(jù)。
因為需要一層一層遞進(jìn)復(fù)制,很容想到用遞歸的方式,參考如下實現(xiàn):
function deepCopy(source) { // 如果不是對象或者是null則直接返回 if (typeof source !== 'object' || source === null) { return source; } let target = {}; // 遍歷復(fù)制屬性 for (let k in source) { if (!source.hasOwnProperty(k)) { continue; } if (typeof source[k] === 'object') { // 如果是對象,則遞歸復(fù)制 target[k] = deepCopy(source[k]); continue; } let descriptor = Object.getOwnPropertyDescriptor(source, k); Object.defineProperty(target, k, descriptor); } return target; }
因為是一層一層復(fù)制,所以復(fù)制完成后,兩個對象不會互相影響,并且也可以支持方法。
let object1 = { a: 1, b: { // b是對象 b1: 2 }, f: function() { // f是方法 console.log(3); } }; object2 = deepCopy(object1); // 深拷貝,也可以復(fù)制函數(shù)了。 object1.f(); // 3 object2.f(); // 3 // b是對象,也不會互相影響 object1.b.b1 = 20; console.log(object1.b.b1); // 20 console.log(object2.b.b1); // 2
復(fù)制原型對象
但是這個方法還存在一個問題,就是原型對象無法復(fù)制,稍微改進(jìn)一下:
// 把 let target = {}; 改成如下方式 // 保證原型也進(jìn)行了復(fù)制 let target = Object.create(Object.getPrototypeOf(source));
這樣就可以了,來個示例驗證一下:
function Human() { this.id = 1; } Human.prototype.bar = function() { console.log("bar"); }; let human1 = new Human(); human2 = deepCopy(human1); console.log("human1", human1); console.log("human2", human2);
查看下兩個對象的原型:
深拷貝復(fù)制原型對象:
完美復(fù)制。
當(dāng)然這樣的方法也存在一個問題,就是遞歸本身存在如果層次過深,容易造成棧溢出的問題。但是在實務(wù)中也建議不要復(fù)制非常大的對象,應(yīng)該有另外好的解決方法。
到此,相信大家對“分析JavaScript淺拷貝和深拷貝”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。