摘要:總結綜上所述,數組的深拷貝比較簡單,方法沒有什么爭議,對象的深拷貝,比較好的方法是用的方法實現,或者遞歸實現,比較簡單的深復制可以使用實現參考資料知乎中的深拷貝和淺拷貝深入剖析的深復制
深淺復制對比
因為JavaScript存儲對象都是存地址的,所以淺復制會導致 obj 和obj1 指向同一塊內存地址。我的理解是,這有點類似數據雙向綁定,改變了其中一方的內容,都是在原來的內存基礎上做修改會導致拷貝對象和源對象都發生改變,而深復制一般都是開辟一塊新的內存地址,將原對象的各個屬性逐個復制出去。對拷貝對象和源對象各自的操作不影響另一方
代碼層面實現深淺復制//數組拷貝
//淺復制,雙向改變,指向同一片內存空間
let arr = [1, 2, 3];
let arr1 = arr;
arr1[1] = "test";
console.log("shallow copy: " + arr + " " + arr1); //shallow copy: 1,test,3 1,test,3
//深復制,開辟新的內存區
//方法一:slice,原理:slice返回一個新數組
let deepArr = [1, 2, 3];
let deepArr1 = deepArr.slice(0);
deepArr1[1] = "test";
console.log("deep copy: " + deepArr + " " + deepArr1); //deep copy: 1,2,3 1,test,3
//方法二:concat,原理:concat返回一個新數組
let deepArr2 = [1, 2, 3];
let deepArr3 = deepArr2.concat();
deepArr3[1] = "test";
console.log("deep copy: " + deepArr2 + " " + deepArr3); //deep copy: 1,2,3 1,test,3
//知乎看到的深復制方法,這個函數可以深拷貝 對象和數組,很遺憾,對象里的函數會丟失
deepCloneObj = obj => {
let str, newobj = obj.constructor === Array ? [] : {};
if(typeof obj !== "object") {
return;
}else if(window.JSON) {
/*好處是非常簡單易用,但是壞處也顯而易見,會丟失很多東西,這會拋棄對象的constructor,
也就是深復制之后,無論這個對象原本的構造函數是什么,在深復制之后都會變成Object。
另外諸如RegExp對象是無法通過這種方式深復制的。
*/
str = JSON.stringify(obj);
newobj = JSON.parse(str);
//console.log(JSON.parse(JSON.stringify(/[0-9]/)));
}else {
for(let i in obj) {
newobj[i] = typeof obj[i] === "object" ? deepCloneObj(obj[i]) : obj[i];
}
}
return newobj;
}
let deepArr4 = {
a: 1,
b: "test",
c: [1, 2, 3],
d: {
"a": "d:a",
"b": "d:b"
}
}
deepArr5 = deepCloneObj(deepArr4);
deepArr5["a"] = "testa";
console.log("deep copy: " + JSON.stringify(deepArr4) + " " + JSON.stringify(deepArr5));
/*deep copy: {"a":1,"b":"test","c":[1,2,3],"d":{"a":"d:a","b":"d:b"}}
{"a":"testa","b":"test","c":[1,2,3],"d":{"a":"d:a","b":"d:b"}}
*/
第三方庫實現深淺復制
1.jQuery.extend
第一個參數可以是布爾值,用來設置是否深度拷貝的:
jQuery.extend(true, { a : { a : "a" } }, { a : { b : "b" } } );
jQuery.extend( { a : { a : "a" } }, { a : { b : "b" } } );
下面是源碼,可以看看
jQuery.extend = jQuery.fn.extend = function() {
var src, copyIsArray, copy, name, options, clone,
target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false;
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
// skip the boolean and the target
target = arguments[ i ] || {};
i++;
}
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
target = {};
}
// extend jQuery itself if only one argument is passed
if ( i === length ) {
target = this;
i--;
}
for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
if ( (options = arguments[ i ]) != null ) {
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
// Prevent never-ending loop
if ( target === copy ) {
continue;
}
// Recurse if we"re merging plain objects or arrays
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
if ( copyIsArray ) {
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : [];
} else {
clone = src && jQuery.isPlainObject(src) ? src : {};
}
// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );
// Don"t bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
// Return the modified object
return target;
};
2.lodash —— _.clone() / _.cloneDeep()
在lodash中關于復制的方法有兩個,分別是_.clone()和_.cloneDeep()。其中_.clone(obj, true)等價于_.cloneDeep(obj)。使用上,lodash和jquery并沒有太大的區別,但看了源碼會發現, jQuery 不過60多行。可 lodash 中與深復制相關的代碼卻有上百行.jQuery 無法正確深復制 JSON 對象以外的對象,lodash 花了大量的代碼來實現 ES6 引入的大量新的標準對象。更厲害的是,lodash 針對存在環的對象的處理也是非常出色的。因此相較而言,lodash 在深復制上的行為反饋比jquery好很多,是更擁抱未來的一個第三方庫。
綜上所述,數組的深拷貝比較簡單,方法沒有什么爭議,對象的深拷貝,比較好的方法是用lodash的方法實現,或者遞歸實現,比較簡單的深復制可以使用JSON.parse(JSON.stringify(obj))實現
參考資料知乎:javascript中的深拷貝和淺拷貝
深入剖析 JavaScript 的深復制
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://www.hztianpu.com/yun/79930.html
摘要:二這么分的好處就是在于節省內存資源,便于合理回收內存詳解中的深淺復制有了上面的鋪墊,那么我們理解起深淺復制就變得容易的許多。 前言 對于前端開發來說,我們經常能夠遇到的問題就是js的深淺復制問題,通常情況下我們解決這個問題的方法就是用JSON.parse(JSON.Stringify(xx))轉換或者用類似于Inmmutable這種第三方庫來進行深復制,但是我們還是要弄懂其中原理,這樣...
摘要:深拷貝相比于淺拷貝速度較慢并且花銷較大。所以在賦值完成后,在棧內存就有兩個指針指向堆內存同一個數據。結果如下擴展運算符只能對一層進行深拷貝如果拷貝的層數超過了一層的話,那么就會進行淺拷貝那么我們可以看到和展開原算符對于深淺拷貝的結果是一樣。 JS中數據類型 基本數據類型: undefined、null、Boolean、Number、String和Symbol(ES6) 引用數據類型:...
摘要:基本數據類型的復制很簡單,就是賦值操作,所以深淺拷貝也是針對,這類引用類型數據。它會拋棄對象的。另外,查資料過程中還看到這么一個詞結構化克隆算法還有這一篇資料也有參考,也寫得比較詳細了的深淺拷貝 基本數據類型的復制很簡單,就是賦值操作,所以深淺拷貝也是針對Object,Array這類引用類型數據。 淺拷貝對于字符串來說,是值的復制,而對于對象來說則是對對象地址的復制;而深拷貝的話,它不...
閱讀 1150·2021-10-09 09:58
閱讀 895·2021-08-27 16:24
閱讀 1986·2019-08-30 14:15
閱讀 2658·2019-08-30 11:04
閱讀 2349·2019-08-29 18:43
閱讀 2390·2019-08-29 15:20
閱讀 3018·2019-08-26 12:20
閱讀 1952·2019-08-26 11:44