摘要:總結(jié)綜上所述,數(shù)組的深拷貝比較簡(jiǎn)單,方法沒有什么爭(zhēng)議,對(duì)象的深拷貝,比較好的方法是用的方法實(shí)現(xiàn),或者遞歸實(shí)現(xiàn),比較簡(jiǎn)單的深復(fù)制可以使用實(shí)現(xiàn)參考資料知乎中的深拷貝和淺拷貝深入剖析的深復(fù)制
深淺復(fù)制對(duì)比
因?yàn)镴avaScript存儲(chǔ)對(duì)象都是存地址的,所以淺復(fù)制會(huì)導(dǎo)致 obj 和obj1 指向同一塊內(nèi)存地址。我的理解是,這有點(diǎn)類似數(shù)據(jù)雙向綁定,改變了其中一方的內(nèi)容,都是在原來的內(nèi)存基礎(chǔ)上做修改會(huì)導(dǎo)致拷貝對(duì)象和源對(duì)象都發(fā)生改變,而深復(fù)制一般都是開辟一塊新的內(nèi)存地址,將原對(duì)象的各個(gè)屬性逐個(gè)復(fù)制出去。對(duì)拷貝對(duì)象和源對(duì)象各自的操作不影響另一方
代碼層面實(shí)現(xiàn)深淺復(fù)制//數(shù)組拷貝 //淺復(fù)制,雙向改變,指向同一片內(nèi)存空間 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 //深復(fù)制,開辟新的內(nèi)存區(qū) //方法一:slice,原理:slice返回一個(gè)新數(shù)組 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返回一個(gè)新數(shù)組 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 //知乎看到的深復(fù)制方法,這個(gè)函數(shù)可以深拷貝 對(duì)象和數(shù)組,很遺憾,對(duì)象里的函數(shù)會(huì)丟失 deepCloneObj = obj => { let str, newobj = obj.constructor === Array ? [] : {}; if(typeof obj !== "object") { return; }else if(window.JSON) { /*好處是非常簡(jiǎn)單易用,但是壞處也顯而易見,會(huì)丟失很多東西,這會(huì)拋棄對(duì)象的constructor, 也就是深復(fù)制之后,無論這個(gè)對(duì)象原本的構(gòu)造函數(shù)是什么,在深復(fù)制之后都會(huì)變成Object。 另外諸如RegExp對(duì)象是無法通過這種方式深復(fù)制的。 */ 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"}} */第三方庫實(shí)現(xiàn)深淺復(fù)制
1.jQuery.extend
第一個(gè)參數(shù)可以是布爾值,用來設(shè)置是否深度拷貝的:
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中關(guān)于復(fù)制的方法有兩個(gè),分別是_.clone()和_.cloneDeep()。其中_.clone(obj, true)等價(jià)于_.cloneDeep(obj)。使用上,lodash和jquery并沒有太大的區(qū)別,但看了源碼會(huì)發(fā)現(xiàn), jQuery 不過60多行。可 lodash 中與深復(fù)制相關(guān)的代碼卻有上百行.jQuery 無法正確深復(fù)制 JSON 對(duì)象以外的對(duì)象,lodash 花了大量的代碼來實(shí)現(xiàn) ES6 引入的大量新的標(biāo)準(zhǔn)對(duì)象。更厲害的是,lodash 針對(duì)存在環(huán)的對(duì)象的處理也是非常出色的。因此相較而言,lodash 在深復(fù)制上的行為反饋比jquery好很多,是更擁抱未來的一個(gè)第三方庫。
綜上所述,數(shù)組的深拷貝比較簡(jiǎn)單,方法沒有什么爭(zhēng)議,對(duì)象的深拷貝,比較好的方法是用lodash的方法實(shí)現(xiàn),或者遞歸實(shí)現(xiàn),比較簡(jiǎn)單的深復(fù)制可以使用JSON.parse(JSON.stringify(obj))實(shí)現(xiàn)
參考資料知乎:javascript中的深拷貝和淺拷貝
深入剖析 JavaScript 的深復(fù)制
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/79930.html
摘要:在之前的文章專題之?dāng)?shù)據(jù)類型和類型檢測(cè)中我有講過,中的數(shù)據(jù)類型分為兩種,基本數(shù)據(jù)類型和引用數(shù)據(jù)類型,基本數(shù)據(jù)類型是保存在棧的數(shù)據(jù)結(jié)構(gòu)中的是按值訪問,所以不存在深淺拷貝問題。 前言 在開發(fā)過程中,偶爾會(huì)遇到這種場(chǎng)景,拿到一個(gè)數(shù)據(jù)后,你打算對(duì)它進(jìn)行處理,但是你又希望拷貝一份副本出來,方便數(shù)據(jù)對(duì)比和以后恢復(fù)數(shù)據(jù)。 那么這就涉及到了 JS 中對(duì)數(shù)據(jù)的深淺拷貝問題,所謂深淺拷貝,淺拷貝的意思就是,...
摘要:二這么分的好處就是在于節(jié)省內(nèi)存資源,便于合理回收內(nèi)存詳解中的深淺復(fù)制有了上面的鋪墊,那么我們理解起深淺復(fù)制就變得容易的許多。 前言 對(duì)于前端開發(fā)來說,我們經(jīng)常能夠遇到的問題就是js的深淺復(fù)制問題,通常情況下我們解決這個(gè)問題的方法就是用JSON.parse(JSON.Stringify(xx))轉(zhuǎn)換或者用類似于Inmmutable這種第三方庫來進(jìn)行深復(fù)制,但是我們還是要弄懂其中原理,這樣...
摘要:從而也引出了所謂的深淺復(fù)制問題。附注對(duì)于淺復(fù)制,其實(shí)還有其他的實(shí)現(xiàn)方式,比如數(shù)組中和方法,對(duì)于這些還是希望大家自己了解,本本主要針對(duì)深淺復(fù)制的實(shí)現(xiàn)原理進(jìn)行解析。 前言 在之前寫繼承的過程談到了深淺復(fù)制的問題,因?yàn)橛凶x者反映到需要解析,趁今天周末寫一篇解析,今天的主體相對(duì)之前來說理解難度低一些,篇幅可能也比較短,諸君按需閱讀即可。 從兩種數(shù)據(jù)類型說起 在js中,變量的類型可以大致分成兩種...
摘要:深拷貝相比于淺拷貝速度較慢并且花銷較大。所以在賦值完成后,在棧內(nèi)存就有兩個(gè)指針指向堆內(nèi)存同一個(gè)數(shù)據(jù)。結(jié)果如下擴(kuò)展運(yùn)算符只能對(duì)一層進(jìn)行深拷貝如果拷貝的層數(shù)超過了一層的話,那么就會(huì)進(jìn)行淺拷貝那么我們可以看到和展開原算符對(duì)于深淺拷貝的結(jié)果是一樣。 JS中數(shù)據(jù)類型 基本數(shù)據(jù)類型: undefined、null、Boolean、Number、String和Symbol(ES6) 引用數(shù)據(jù)類型:...
摘要:基本數(shù)據(jù)類型的復(fù)制很簡(jiǎn)單,就是賦值操作,所以深淺拷貝也是針對(duì),這類引用類型數(shù)據(jù)。它會(huì)拋棄對(duì)象的。另外,查資料過程中還看到這么一個(gè)詞結(jié)構(gòu)化克隆算法還有這一篇資料也有參考,也寫得比較詳細(xì)了的深淺拷貝 基本數(shù)據(jù)類型的復(fù)制很簡(jiǎn)單,就是賦值操作,所以深淺拷貝也是針對(duì)Object,Array這類引用類型數(shù)據(jù)。 淺拷貝對(duì)于字符串來說,是值的復(fù)制,而對(duì)于對(duì)象來說則是對(duì)對(duì)象地址的復(fù)制;而深拷貝的話,它不...
閱讀 767·2021-10-09 09:58
閱讀 634·2021-08-27 16:24
閱讀 1719·2019-08-30 14:15
閱讀 2376·2019-08-30 11:04
閱讀 2061·2019-08-29 18:43
閱讀 2166·2019-08-29 15:20
閱讀 2712·2019-08-26 12:20
閱讀 1612·2019-08-26 11:44