摘要:那么如何切斷和之間的關(guān)系呢,可以拷貝一份的數(shù)據(jù),根據(jù)拷貝的層級不同可以分為淺拷貝和深拷貝,淺拷貝就是只進(jìn)行一層拷貝,深拷貝就是無限層級拷貝。
深拷貝 vs 淺拷貝
深拷貝和淺拷貝都是針對的引用類型,JS中的變量類型分為值類型(基本類型)和引用類型;對值類型進(jìn)行復(fù)制操作會(huì)對值進(jìn)行一份拷貝,而對引用類型賦值,則會(huì)進(jìn)行地址的拷貝,最終兩個(gè)變量指向同一份數(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ù)
對于引用類型,會(huì)導(dǎo)致a b指向同一份數(shù)據(jù),此時(shí)如果對其中一個(gè)進(jìn)行修改,就會(huì)影響到另外一個(gè),有時(shí)候這可能不是我們想要的結(jié)果,如果對這種現(xiàn)象不清楚的話,還可能造成不必要的bug。那么如何切斷a和b之間的關(guān)系呢,可以拷貝一份a的數(shù)據(jù),根據(jù)拷貝的層級不同可以分為淺拷貝和深拷貝,淺拷貝就是只進(jìn)行一層拷貝,深拷貝就是無限層級拷貝。
深復(fù)制和淺復(fù)制最根本的區(qū)別在于是否是真正獲取了一個(gè)對象的復(fù)制實(shí)體,而不是引用
深復(fù)制在計(jì)算機(jī)中開辟了一塊內(nèi)存地址用于存放復(fù)制的對象,
淺復(fù)制僅僅是指向被復(fù)制的內(nèi)存地址,如果原地址中對象被改變了,那么淺復(fù)制出來的對象也會(huì)相應(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ù)制后也是會(huì)發(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í)可以分解成兩個(gè)問題,淺拷貝+遞歸,什么意思呢?假設(shè)我們有如下數(shù)據(jù)
var a1 = {b: {c: {d: 1}};
只需稍加改動(dòng)上面淺拷貝的代碼即可,注意區(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í)上面的代碼問題太多了,先來舉幾個(gè)例子吧
沒有對參數(shù)做檢驗(yàn)
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ù)的層次很深是就會(huì)棧溢出
方法: 用系統(tǒng)自帶的JSON來做深拷貝的例子,下面來看下代碼實(shí)現(xiàn)
function cloneJSON(source) { return JSON.parse(JSON.stringify(source)); }
但是cloneJSON也有缺點(diǎn),它的內(nèi)部也是使用遞歸的方式
cloneJSON(createData(10000)); // Maximum call stack size exceeded
既然是用了遞歸,那循環(huán)引用呢?并沒有因?yàn)樗姥h(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ù)制有新的兩種方法,不會(huì)發(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
第二種這個(gè)方法也可以用在函數(shù)的行參上面。
function show(...arr1){ //直接來復(fù)制arguments這個(gè)偽數(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://systransis.cn/yun/100128.html
摘要:深拷貝淺拷貝本文主要對深拷貝淺拷貝的解釋及實(shí)現(xiàn)做一下簡單記錄。之所以會(huì)有深拷貝與淺拷貝之分,是因?yàn)椴煌瑪?shù)據(jù)類型的數(shù)據(jù)在內(nèi)存中的存儲(chǔ)區(qū)域不一樣。但注意,只能做一層屬性的淺拷貝。 深拷貝VS淺拷貝 本文主要對深拷貝&淺拷貝的解釋及實(shí)現(xiàn)做一下簡單記錄。原文鏈接,歡迎star。 之所以會(huì)有深拷貝與淺拷貝之分,是因?yàn)椴煌瑪?shù)據(jù)類型的數(shù)據(jù)在內(nèi)存中的存儲(chǔ)區(qū)域不一樣。 堆和棧是計(jì)算機(jī)中劃分出來用來存儲(chǔ)的...
摘要:而在這個(gè)運(yùn)算符的相關(guān)用例中,往往會(huì)涉及到其他知識點(diǎn),深拷貝和淺拷貝就是其中之一。即對象的淺拷貝會(huì)對主對象的值進(jìn)行拷貝,而該值有可能是一個(gè)指針,指向內(nèi)存中的同一個(gè)對象。,可以看到深拷貝和淺拷貝是對復(fù)制引用類型變量而言的。 在ES6的系列文章中,基本都會(huì)提到Spread——擴(kuò)展運(yùn)算符(...)。而在這個(gè)運(yùn)算符的相關(guān)用例中,往往會(huì)涉及到其他知識點(diǎn),深拷貝和淺拷貝就是其中之一。 背景知識 在討...
摘要:二淺拷貝與深拷貝深拷貝和淺拷貝是只針對和這樣的引用數(shù)據(jù)類型的。淺拷貝是按位拷貝對象,它會(huì)創(chuàng)建一個(gè)新對象,這個(gè)對象有著原始對象屬性值的一份精確拷貝。對于字符串?dāng)?shù)字及布爾值來說不是或者對象,會(huì)拷貝這些值到新的數(shù)組里。 一、數(shù)據(jù)類型 數(shù)據(jù)分為基本數(shù)據(jù)類型(String, Number, Boolean, Null, Undefined,Symbol)和對象數(shù)據(jù)類型。 基本數(shù)據(jù)類型的特點(diǎn):直...
摘要:二淺拷貝與深拷貝深拷貝和淺拷貝是只針對和這樣的引用數(shù)據(jù)類型的。淺拷貝是按位拷貝對象,它會(huì)創(chuàng)建一個(gè)新對象,這個(gè)對象有著原始對象屬性值的一份精確拷貝。對于字符串?dāng)?shù)字及布爾值來說不是或者對象,會(huì)拷貝這些值到新的數(shù)組里。 一、數(shù)據(jù)類型 數(shù)據(jù)分為基本數(shù)據(jù)類型(String, Number, Boolean, Null, Undefined,Symbol)和對象數(shù)據(jù)類型。 基本數(shù)據(jù)類型的特點(diǎn):直...
閱讀 2916·2021-11-25 09:43
閱讀 2342·2021-11-24 09:39
閱讀 2728·2021-09-23 11:51
閱讀 1418·2021-09-07 10:11
閱讀 1467·2019-08-27 10:52
閱讀 1949·2019-08-26 12:13
閱讀 3369·2019-08-26 11:57
閱讀 1407·2019-08-26 11:31