摘要:在中可以通過添加一個參數(shù)來實現(xiàn)遞歸,調(diào)用就可以實現(xiàn)一個深拷貝。利用序列化實現(xiàn)一個深拷貝
在JavaScript中,對于Object和Array這類引用類型值,當(dāng)從一個變量向另一個變量復(fù)制引用類型值時,這個值的副本其實是一個指針,兩個變量指向同一個堆對象,改變其中一個變量,另一個也會受到影響。
這種拷貝分為兩種情況:拷貝引用和拷貝實例,也就是我們說的淺拷貝和深拷貝
淺拷貝(shallow copy)拷貝原對象的引用,這是最簡單的淺拷貝。
// 對象 var o1 = {a: 1}; var o2 = o1; console.log(o1 === o2); // =>true o2.a = 2; console.log(o1.a); // => 2 // 數(shù)組 var o1 = [1,2,3]; var o2 = o1; console.log(o1 === o2); // => true o2.push(4); console.log(o1); // => [1,2,3,4]
拷貝原對象的實例,但是對其內(nèi)部的引用類型值,拷貝的是其引用,常用的就是如jquey中的$.extend({}, obj); Array.prototype.slice()和Array.prototype.concat()都會返回一個數(shù)組或者對象的淺拷貝,舉個例子:
var o1 = ["darko", {age: 22}]; var o2 = o1.slice(); // 根據(jù)Array.prototype.slice()的特性,這里會返回一個o1的淺拷貝對象 console.log(o1 === o2); // => false,說明o2拷貝的是o1的一個實例 o2[0] = "lee"; console.log(o1[0]); // => "darko" o1和o2內(nèi)部包含的基本類型值,復(fù)制的是其實例,不會相互影響 o2[1].age = 23; console.log(o1[1].age); // =>23 o1和o2內(nèi)部包含的引用類型值,復(fù)制的是其引用,會相互影響
可以通過Array.prototype.slice()或jQuery中的$.extend({}, obj)完成對一個數(shù)組或者對象的淺拷貝,我們也可以自己寫一個簡單淺拷貝函數(shù)來加深對淺拷貝的理解、
// 淺拷貝實現(xiàn),僅供參考 function shallowClone(source) { if (!source || typeof source !== "object") { throw new Error("error arguments"); } var targetObj = source.constructor === Array ? [] : {}; for (var keys in source) { if (source.hasOwnProperty(keys)) { targetObj[keys] = source[keys]; } } return targetObj; }深拷貝(deep copy)
深拷貝也就是拷貝出一個新的實例,新的實例和之前的實例互不影響,深拷貝的實現(xiàn)有幾種方法,首先我們可以借助jQuery,lodash等第三方庫完成一個深拷貝實例。在jQuery中可以通過添加一個參數(shù)來實現(xiàn)遞歸extend,調(diào)用$.extend(true, {}, ...)就可以實現(xiàn)一個深拷貝。
我們也可以自己實現(xiàn)一個深拷貝的函數(shù),通常有兩種方式,一種就是用遞歸的方式來做,還有一種是利用JSON.stringify和JSON.parse來做,這兩種方式各有優(yōu)劣,先來看看遞歸的方法怎么做。
jQuery中的extend方法基本的就是按照這個思路實現(xiàn)的,但是沒有辦法處理源對象內(nèi)部循環(huán)引用的問題,同時對Date,F(xiàn)uncion等類型值也沒有實現(xiàn)真正的深度復(fù)制,但是這些類型的值在重新定義的時候一般都是直接覆蓋,所以也不會對源對象產(chǎn)生影響,從一定程度上來說也算是實現(xiàn)了一個深拷貝。
// 遞歸實現(xiàn)一個深拷貝 function deepClone(source){ if(!source || typeof source !== "object"){ throw new Error("error arguments", "shallowClone"); } var targetObj = source.constructor === Array ? [] : {}; for(var keys in source){ if(source.hasOwnProperty(keys)){ if(source[keys] && typeof source[keys] === "object"){ targetObj[keys] = source[keys].constructor === Array ? [] : {}; targetObj[keys] = deepClone(source[keys]); }else{ targetObj[keys] = source[keys]; } } } return targetObj; } // test example var o1 = { arr: [1, 2, 3], obj: { key: "value" }, func: function(){ return 1; } }; var o3 = deepClone(o1); console.log(o3 === o1); // => false console.log(o3.obj === o1.obj); // => false console.log(o2.func === o1.func); // => true
還有一種實現(xiàn)深拷貝的方式是利用JSON對象中的parse和stringify,JOSN對象中的stringify可以把一個js對象序列化為一個JSON字符串,parse可以把JSON字符串反序列化為一個js對象,通過這兩個方法,也可以實現(xiàn)對象的深復(fù)制。
我們從下面的例子就可以看到,源對象的方法在拷貝的過程中丟失了,這是因為在序列化JavaScript對象時,所有函數(shù)和原型成員會被有意忽略,這個實現(xiàn)可以滿足一些比較簡單的情況,能夠處理JSON格式所能表示的所有數(shù)據(jù)類型,同時如果在對象中存在循環(huán)應(yīng)用的情況也無法正確處理。
// 利用JSON序列化實現(xiàn)一個深拷貝 function deepClone(source){ return JSON.parse(JSON.stringify(source)); } var o1 = { arr: [1, 2, 3], obj: { key: "value" }, func: function(){ return 1; } }; var o2 = deepClone(o1); console.log(o2); // => {arr: [1,2,3], obj: {key: "value"}}
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/86872.html
摘要:引用類型值引用類型值是保存在堆內(nèi)存中的對象,變量保存的只是指向該內(nèi)存的地址,在復(fù)制引用類型值的時候,其實只復(fù)制了指向該內(nèi)存的地址。 前言 要理解 JavaScript中淺拷貝和深拷貝的區(qū)別,首先要明白JavaScript的數(shù)據(jù)類型。JavaScript有兩種數(shù)據(jù)類型,基礎(chǔ)數(shù)據(jù)類型和引用數(shù)據(jù)類型。js的基本類型:undefined,null,string,boolean,number,s...
摘要:說明外層數(shù)組拷貝的是實例說明元素拷貝是引用深拷貝在堆中重新分配內(nèi)存,并且把源對象所有屬性都進行新建拷貝,拷貝后的對象與原來的對象完全隔離,互不影響。中的方法可以實現(xiàn)深拷貝,源碼原理也是遞歸使用淺拷貝。 1.淺拷貝 當(dāng)把數(shù)組或?qū)ο蠛唵钨x值給其他變量的時候,實際上進行的是淺拷貝,淺拷貝是拷貝引用,只是將拷貝后的引用指向同一個對象實例,彼此間的操作還會互相影響。 分為兩種情況:直接拷貝源對象...
摘要:但是進行的是淺拷貝,拷貝的是屬性值。對象展開符深拷貝的實現(xiàn)方式手動復(fù)制轉(zhuǎn)成再轉(zhuǎn)回來只有可以轉(zhuǎn)成格式的對象才可以這樣用,像沒辦法轉(zhuǎn)成沒被改到使用方法避免相互引用對象導(dǎo)致死循環(huán),如的情況四參考關(guān)于的淺拷貝和深拷貝 一、理解 淺拷貝只復(fù)制指向某個對象的指針,而不復(fù)制對象本身,新舊對象還是共享同一塊內(nèi)存。但深拷貝會另外創(chuàng)造一個一模一樣的對象,新對象跟原對象不共享內(nèi)存,修改新對象不會改到原對象。...
摘要:淺拷貝和淺拷貝的問題,不僅在日常應(yīng)用中需要注意,而且在面試和筆試中也常被用來考察應(yīng)聘者,屬于文體兩開花的?;緮?shù)據(jù)類型引用數(shù)據(jù)類型等等基本數(shù)據(jù)類型是按值訪問的,對其的拷貝會直接復(fù)制其值保存在新變量中。方法手工遍歷法方法方法方法方法 淺拷貝和淺拷貝的問題,不僅在日常應(yīng)用中需要注意,而且在面試和筆試中也常被用來考察應(yīng)聘者,屬于文體兩開花的points。 什么是深拷貝和淺拷貝呢? 名稱 ...
摘要:拷貝分為淺拷貝和深拷貝。淺拷貝是引用復(fù)制,深拷貝是完全單純拷貝數(shù)據(jù)的值。所以,這種方法只是簡單繞過第一層箱子的引用復(fù)制深拷貝目前比較好的方法就是大法,要么就是自己寫遞歸的深拷貝函數(shù)。附帶深拷貝的自定義函數(shù)源自大佬的 經(jīng)常遇到數(shù)組或?qū)ο蟮纫妙愋妥鳛楹瘮?shù)的參數(shù)的情況,但又不想修改原來的數(shù)據(jù),這時候就需要拷貝(基本類型的變量不需要考慮)??截惙譃闇\拷貝和深拷貝。淺拷貝是引用復(fù)制,深拷貝是完...
閱讀 484·2024-11-07 18:25
閱讀 130851·2024-02-01 10:43
閱讀 961·2024-01-31 14:58
閱讀 925·2024-01-31 14:54
閱讀 83048·2024-01-29 17:11
閱讀 3310·2024-01-25 14:55
閱讀 2086·2023-06-02 13:36
閱讀 3206·2023-05-23 10:26