日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

关于JavaScript的浅拷贝和深拷贝

發(fā)布時間:2023/12/18 javascript 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 关于JavaScript的浅拷贝和深拷贝 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在?JS?中有一些基本類型像是Number、String、Boolean,而對象就是像這樣的東西{?name:?'Larry',?skill:?'Node.js'?},對象跟基本類型最大的不同就在于他們的傳值方式。

基本類型是按值傳遞,像是這樣:在修改a時并不會改到b

var a = 25; var b = a; b = 18; console.log(a);//25 console.log(b);//18

但對象就不同,對象傳的是按引用傳值:

var obj1 = { a: 10, b: 20, c: 30 }; var obj2 = obj1; obj2.b = 100; console.log(obj1); // { a: 10, b: 100, c: 30 } <-- b 被改到了 console.log(obj2); // { a: 10, b: 100, c: 30 }

復(fù)制一份obj1叫做obj2,然后把obj2.b改成100,但卻不小心改到obj1.b,因為他們根本是同一個對象,這就是所謂的淺拷貝。

要避免這樣的錯誤發(fā)生就要寫成這樣:

var obj1 = { a: 10, b: 20, c: 30 }; var obj2 = { a: obj1.a, b: obj1.b, c: obj1.c }; obj2.b = 100; console.log(obj1); // { a: 10, b: 20, c: 30 } <-- b 沒被改到 console.log(obj2); // { a: 10, b: 100, c: 30 }

這樣就是深拷貝,不會改到原本的obj1。

淺拷貝(Shallow Copy) VS?深拷貝(Deep Copy)

淺拷貝只復(fù)制指向某個對象的指針,而不復(fù)制對象本身,新舊對象還是共享同一塊內(nèi)存。但深拷貝會另外創(chuàng)造一個一模一樣的對象,新對象跟原對象不共享內(nèi)存,修改新對象不會改到原對象。

淺拷貝的實現(xiàn)方式

也就是簡單地復(fù)制而已

1、簡單地復(fù)制語句

<script type="text/javascript">function simpleClone(initalObj) { var obj = {}; for ( var i in initalObj) {obj[i] = initalObj[i];} return obj;}var obj = {a: "hello",b:{a: "world",b: 21},c:["Bob", "Tom", "Jenny"],d:function() {alert("hello world");}}var cloneObj = simpleClone(obj); console.log(cloneObj.b); console.log(cloneObj.c);console.log(cloneObj.d);cloneObj.b.a = "changed";cloneObj.c = [1, 2, 3];cloneObj.d = function() { alert("changed"); };console.log(obj.b);console.log(obj.c);console.log(obj.d);</script>

結(jié)果為:

2、Object.assign()

Object.assign是ES6的新函數(shù)。Object.assign()?方法可以把任意多個的源對象自身的可枚舉屬性拷貝給目標(biāo)對象,然后返回目標(biāo)對象。但是?Object.assign()?進(jìn)行的是淺拷貝,拷貝的是對象的屬性的引用,而不是對象本身。

Object.assign(target, ...sources)

參數(shù):

target:目標(biāo)對象。
sources:任意多個源對象。
返回值:目標(biāo)對象會被返回。

var obj = { a: {a: "hello", b: 21} }; var initalObj = Object.assign({}, obj);initalObj.a.a = "changed"; console.log(obj.a.a); // "changed"

兼容性:

需要注意的是:

Object.assign()可以處理一層的深度拷貝,如下: var obj1 = { a: 10, b: 20, c: 30 }; var obj2 = Object.assign({}, obj1); obj2.b = 100; console.log(obj1); // { a: 10, b: 20, c: 30 } <-- 沒被改到 console.log(obj2); // { a: 10, b: 100, c: 30 }

深拷貝的實現(xiàn)方式

要完全復(fù)制又不能修改到原對象,這時候就要用?Deep Copy,這里會介紹幾種Deep Copy?的方式。

1、手動復(fù)制

把一個對象的屬性復(fù)制給另一個對象的屬性

var obj1 = { a: 10, b: 20, c: 30 }; var obj2 = { a: obj1.a, b: obj1.b, c: obj1.c }; obj2.b = 100; console.log(obj1); // { a: 10, b: 20, c: 30 } <-- 沒被改到 console.log(obj2); // { a: 10, b: 100, c: 30 }

但這樣很麻煩,要一個一個自己復(fù)制;而且這樣的本質(zhì)也不能算是 Deep Copy,因為對象里面也可能回事對象,如像下面這個狀況:

var obj1 = { body: { a: 10 } }; var obj2 = { body: obj1.body }; obj2.body.a = 20; console.log(obj1); // { body: { a: 20 } } <-- 被改到了 console.log(obj2); // { body: { a: 20 } } console.log(obj1 === obj2); // false console.log(obj1.body === obj2.body); // true

雖然obj1跟obj2是不同對象,但他們會共享同一個obj1.body,所以修改obj2.body.a時也會修改到舊的。

2、對象只有一層的話可以使用上面的:Object.assign()函數(shù)

Object.assign({}, obj1)的意思是先建立一個空對象{},接著把obj1中所有的屬性復(fù)制過去,所以obj2會長得跟obj1一樣,這時候再修改obj2.b也不會影響obj1。

因為Object.assign跟我們手動復(fù)制的效果相同,所以一樣只能處理深度只有一層的對象,沒辦法做到真正的?Deep Copy。不過如果要復(fù)制的對象只有一層的話可以考慮使用它。

3、轉(zhuǎn)成?JSON?再轉(zhuǎn)回來

用JSON.stringify把對象轉(zhuǎn)成字符串,再用JSON.parse把字符串轉(zhuǎn)成新的對象。

var obj1 = { body: { a: 10 } }; var obj2 = JSON.parse(JSON.stringify(obj1)); obj2.body.a = 20; console.log(obj1); // { body: { a: 10 } } <-- 沒被改到 console.log(obj2); // { body: { a: 20 } } console.log(obj1 === obj2); // false console.log(obj1.body === obj2.body); // false

這樣做是真正的Deep Copy,這種方法簡單易用。

但是這種方法也有不少壞處,譬如它會拋棄對象的constructor。也就是深拷貝之后,不管這個對象原來的構(gòu)造函數(shù)是什么,在深拷貝之后都會變成Object。

這種方法能正確處理的對象只有?Number, String, Boolean, Array, 扁平對象,即那些能夠被 json 直接表示的數(shù)據(jù)結(jié)構(gòu)。RegExp對象是無法通過這種方式深拷貝。

也就是說,只有可以轉(zhuǎn)成JSON格式的對象才可以這樣用,像function沒辦法轉(zhuǎn)成JSON。

var obj1 = { fun: function(){ console.log(123) } }; var obj2 = JSON.parse(JSON.stringify(obj1)); console.log(typeof obj1.fun); // 'function' console.log(typeof obj2.fun); // 'undefined' <-- 沒復(fù)制

要復(fù)制的function會直接消失,所以這個方法只能用在單純只有數(shù)據(jù)的對象。

4、遞歸拷貝

function deepClone(initalObj, finalObj) { var obj = finalObj || {}; for (var i in initalObj) { if (typeof initalObj[i] === 'object') {obj[i] = (initalObj[i].constructor === Array) ? [] : {}; arguments.callee(initalObj[i], obj[i]);} else {obj[i] = initalObj[i];}} return obj; } var str = {}; var obj = { a: {a: "hello", b: 21} }; deepClone(obj, str); console.log(str.a);

上述代碼確實可以實現(xiàn)深拷貝。但是當(dāng)遇到兩個互相引用的對象,會出現(xiàn)死循環(huán)的情況。

為了避免相互引用的對象導(dǎo)致死循環(huán)的情況,則應(yīng)該在遍歷的時候判斷是否相互引用對象,如果是則退出循環(huán)。

改進(jìn)版代碼如下:

function deepClone(initalObj, finalObj) { var obj = finalObj || {}; for (var i in initalObj) { var prop = initalObj[i]; // 避免相互引用對象導(dǎo)致死循環(huán),如initalObj.a = initalObj的情況if(prop === obj) { continue;} if (typeof prop === 'object') {obj[i] = (prop.constructor === Array) ? [] : {}; arguments.callee(prop, obj[i]);} else {obj[i] = prop;}} return obj; } var str = {}; var obj = { a: {a: "hello", b: 21} }; deepClone(obj, str); console.log(str.a);

5、使用Object.create()方法

直接使用var newObj = Object.create(oldObj),可以達(dá)到深拷貝的效果。

function deepClone(initalObj, finalObj) { var obj = finalObj || {}; for (var i in initalObj) { var prop = initalObj[i]; // 避免相互引用對象導(dǎo)致死循環(huán),如initalObj.a = initalObj的情況if(prop === obj) { continue;} if (typeof prop === 'object') {obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);} else {obj[i] = prop;}} return obj; }

6、jquery

jquery?有提供一個$.extend可以用來做?Deep Copy。

var $ = require('jquery'); var obj1 = {a: 1,b: { f: { g: 1 } },c: [1, 2, 3] }; var obj2 = $.extend(true, {}, obj1); console.log(obj1.b.f === obj2.b.f); // false

7、lodash

另外一個很熱門的函數(shù)庫lodash,也有提供_.cloneDeep用來做?Deep Copy。

var _ = require('lodash'); var obj1 = {a: 1,b: { f: { g: 1 } },c: [1, 2, 3] }; var obj2 = _.cloneDeep(obj1); console.log(obj1.b.f === obj2.b.f); // false

這個性能還不錯,使用起來也很簡單。

?

?

?

?

?

參考:

JavaScript 中對象的深拷貝

關(guān)于 JS 中的淺拷貝和深拷貝

?

轉(zhuǎn)載于:https://www.cnblogs.com/Chen-XiaoJun/p/6217373.html

總結(jié)

以上是生活随笔為你收集整理的关于JavaScript的浅拷贝和深拷贝的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。