摘要:那么如何切斷和之間的關(guān)系呢,可以拷貝一份的數(shù)據(jù),根據(jù)拷貝的層級不同可以分為淺拷貝和深拷貝,淺拷貝就是只進(jìn)行一層拷貝,深拷貝就是無限層級拷貝。
深拷貝 vs 淺拷貝
深拷貝和淺拷貝都是針對的引用類型,JS中的變量類型分為值類型(基本類型)和引用類型;對值類型進(jìn)行復(fù)制操作會對值進(jìn)行一份拷貝,而對引用類型賦值,則會進(jìn)行地址的拷貝,最終兩個變量指向同一份數(shù)據(jù)。
// 基本類型 var a = 1; var b = a; a = 2; console.log(a, b); // 2, 1 ,a b指向不同的數(shù)據(jù) // 引用類型指向同一份數(shù)據(jù) var a = {c: 1}; var b = a; a.c = 2; console.log(a.c, b.c); // 2, 2 全是2,a b指向同一份數(shù)據(jù)
對于引用類型,會導(dǎo)致a b指向同一份數(shù)據(jù),此時如果對其中一個進(jìn)行修改,就會影響到另外一個,有時候這可能不是我們想要的結(jié)果,如果對這種現(xiàn)象不清楚的話,還可能造成不必要的bug。那么如何切斷a和b之間的關(guān)系呢,可以拷貝一份a的數(shù)據(jù),根據(jù)拷貝的層級不同可以分為淺拷貝和深拷貝,淺拷貝就是只進(jìn)行一層拷貝,深拷貝就是無限層級拷貝。
深復(fù)制和淺復(fù)制最根本的區(qū)別在于是否是真正獲取了一個對象的復(fù)制實體,而不是引用
深復(fù)制在計算機(jī)中開辟了一塊內(nèi)存地址用于存放復(fù)制的對象,
淺復(fù)制僅僅是指向被復(fù)制的內(nèi)存地址,如果原地址中對象被改變了,那么淺復(fù)制出來的對象也會相應(yīng)改變。
var a1 = {b: {c: {}}; var a2 = shallowClone(a1); // 淺拷貝 a2.b.c === a1.b.c // true var a3 = clone(a1); // 深拷貝 a3.b.c === a1.b.c // false
所謂的淺復(fù)制,只是拷貝了基本類型的數(shù)據(jù),而引用類型數(shù)據(jù),復(fù)制后也是會發(fā)生引用,我們把這種拷貝叫做“(淺復(fù)制)淺拷貝”。Object.assign({}, obj1, obj2)
function shallowClone(source) { var target = {}; for(var i in source) { if (source.hasOwnProperty(i)) { target[i] = source[i]; } } return target; }
深拷貝的問題其實可以分解成兩個問題,淺拷貝+遞歸,什么意思呢?假設(shè)我們有如下數(shù)據(jù)
var a1 = {b: {c: {d: 1}};
只需稍加改動上面淺拷貝的代碼即可,注意區(qū)別
function clone(source) { var target = {}; for(var i in source) { if (source.hasOwnProperty(i)) { if (typeof source[i] === "object") { target[i] = clone(source[i]); // 注意這里 } else { target[i] = source[i]; } } } return target; }
其實上面的代碼問題太多了,先來舉幾個例子吧
沒有對參數(shù)做檢驗
function isObject(x) { return Object.prototype.toString.call(x) === "[object Object]"; } function clone(source) { if (!isObject(source)) return source; // xxx }
判斷是否對象的邏輯不夠嚴(yán)謹(jǐn)
沒有考慮數(shù)組的兼容
遞歸方法最大的問題在于爆棧,當(dāng)數(shù)據(jù)的層次很深是就會棧溢出
方法: 用系統(tǒng)自帶的JSON來做深拷貝的例子,下面來看下代碼實現(xiàn)
function cloneJSON(source) { return JSON.parse(JSON.stringify(source)); }
但是cloneJSON也有缺點,它的內(nèi)部也是使用遞歸的方式
cloneJSON(createData(10000)); // Maximum call stack size exceeded
既然是用了遞歸,那循環(huán)引用呢?并沒有因為死循環(huán)而導(dǎo)致棧溢出啊,原來是JSON.stringify內(nèi)部做了循環(huán)引用的檢測,正是我們上面提到破解循環(huán)引用的第一種方法:循環(huán)檢測
var a = {}; a.a = a; cloneJSON(a) // Uncaught TypeError: Converting circular structure to JSON
如何復(fù)制對象而不發(fā)生引用呢,對于數(shù)組,ES6我們復(fù)制有新的兩種方法,不會發(fā)生引用。
第一種:Array.from(要復(fù)制的數(shù)組);
var arr1=[1,2,3]; var arr2=Array.from(arr1); arr1.push(4); alert(arr1); //1234 alert(arr2); //123 arr2.push(5); alert(arr1); //1234 alert(arr2); //1235
第二種:...
var arr1=[1,2,3]; var arr2=[...arr1]; arr1.push(4); alert(arr1); //1234 alert(arr2); //123 arr2.push(5); alert(arr1); //1234 alert(arr2); //1235
第二種這個方法也可以用在函數(shù)的行參上面。
function show(...arr1){ //直接來復(fù)制arguments這個偽數(shù)組,讓它變成真正的數(shù)組,從而擁有數(shù)組的方法。 alert(arr1); //1234 arr1.push(5); alert(arr1); //12345 } show(1,2,3,4)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/100128.html
摘要:深拷貝淺拷貝本文主要對深拷貝淺拷貝的解釋及實現(xiàn)做一下簡單記錄。之所以會有深拷貝與淺拷貝之分,是因為不同數(shù)據(jù)類型的數(shù)據(jù)在內(nèi)存中的存儲區(qū)域不一樣。但注意,只能做一層屬性的淺拷貝。 深拷貝VS淺拷貝 本文主要對深拷貝&淺拷貝的解釋及實現(xiàn)做一下簡單記錄。原文鏈接,歡迎star。 之所以會有深拷貝與淺拷貝之分,是因為不同數(shù)據(jù)類型的數(shù)據(jù)在內(nèi)存中的存儲區(qū)域不一樣。 堆和棧是計算機(jī)中劃分出來用來存儲的...
摘要:而在這個運算符的相關(guān)用例中,往往會涉及到其他知識點,深拷貝和淺拷貝就是其中之一。即對象的淺拷貝會對主對象的值進(jìn)行拷貝,而該值有可能是一個指針,指向內(nèi)存中的同一個對象。,可以看到深拷貝和淺拷貝是對復(fù)制引用類型變量而言的。 在ES6的系列文章中,基本都會提到Spread——擴(kuò)展運算符(...)。而在這個運算符的相關(guān)用例中,往往會涉及到其他知識點,深拷貝和淺拷貝就是其中之一。 背景知識 在討...
閱讀 2915·2021-11-25 09:43
閱讀 2342·2021-11-24 09:39
閱讀 2724·2021-09-23 11:51
閱讀 1416·2021-09-07 10:11
閱讀 1461·2019-08-27 10:52
閱讀 1948·2019-08-26 12:13
閱讀 3369·2019-08-26 11:57
閱讀 1406·2019-08-26 11:31