成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JavaScript·隨記 深拷貝 vs. 淺拷貝

RyanQ / 1355人閱讀

摘要:而在這個(gè)運(yùn)算符的相關(guān)用例中,往往會涉及到其他知識點(diǎn),深拷貝和淺拷貝就是其中之一。即對象的淺拷貝會對主對象的值進(jìn)行拷貝,而該值有可能是一個(gè)指針,指向內(nèi)存中的同一個(gè)對象。,可以看到深拷貝和淺拷貝是對復(fù)制引用類型變量而言的。

在ES6的系列文章中,基本都會提到Spread——擴(kuò)展運(yùn)算符(...)。而在這個(gè)運(yùn)算符的相關(guān)用例中,往往會涉及到其他知識點(diǎn),深拷貝淺拷貝就是其中之一。

背景知識

在討論深拷貝淺拷貝之前,我們先看一個(gè)例子:

let a = "hi";
b = a;
b = "hello";
console.log(a);
// "hi"

let arr1 = [1,2,3];
arr2 = arr1;
arr2[0] = 0;
console.log(arr1);
// [0,2,3]

可以看到:為不同的js變量復(fù)制值時(shí),結(jié)果是不同的。把字符串a的值復(fù)制給b,改變b的值不會影響a的值,而把數(shù)組arr1的值復(fù)制給arr2時(shí),改變arr2的值,arr1的值也跟著改變了。

這是因?yàn)閖s存在兩種不同數(shù)據(jù)類型的值:基本類型值引用類型值。
在訪問這兩種類型的變量時(shí),其訪問方式是不同的。在這里,先記一下結(jié)論:

基本數(shù)據(jù)類型是按值訪問的

引用數(shù)據(jù)類型是按引用訪問的
(實(shí)際上這種說法并不嚴(yán)密,為便于理解,我們先這么記)

什么意思?
JavaScript不允許直接訪問內(nèi)存中的位置,換句話說,不能直接操作對象的內(nèi)存空間。
因此,在操作對象時(shí),我們實(shí)際上是在操作對象的引用,而不是實(shí)際的對象。

從一個(gè)變量向另一個(gè)變量復(fù)制值時(shí)(不管是復(fù)制基本類型還是引用類型),都會先為這個(gè)新變量分配一個(gè)空間,然后把該值復(fù)制到新創(chuàng)建的這個(gè)空間里。
不同的是,在復(fù)制引用類型的值時(shí),實(shí)際上復(fù)制過去的是一個(gè)指針,示例圖如下:

在js中,除了7種基本類型外,其他的都是引用類型,比如Object,Array,Function,所以不難理解:

let obj1 = {name:"hx",age:18};
let obj2 = obj1;
obj2.age = 0;
console.log(obj1);
// {name:"hx",age:0}
“引用類型的值是按引用訪問的”不嚴(yán)密在:當(dāng)復(fù)制保存著對象的某個(gè)變量時(shí),操作的是對象的引用;而當(dāng)為對象添加屬性時(shí),操作的是實(shí)際的對象。 ——靈圖社區(qū)
深拷貝 vs. 淺拷貝

我們先來看一下概念:

淺拷貝:

被復(fù)制對象的所有變量都含有與原來的對象相同的值,而所有的對其他對象的引用仍然指向原來的對象。即對象的淺拷貝會對主對象的進(jìn)行拷貝,而該值有可能是一個(gè)指針,指向內(nèi)存中的同一個(gè)對象。

深拷貝:

深拷貝不僅將原對象的各個(gè)屬性逐個(gè)復(fù)制出去,而且將原對象各個(gè)屬性所包含的對象也依次采用深復(fù)制的方法遞歸復(fù)制到新對象上。所以對一個(gè)對象的修改完全不會影響到另一個(gè)對象。

OK,可以看到深拷貝淺拷貝是對“復(fù)制引用類型變量”而言的。事實(shí)上,也只有在引用類型中才有討論兩者區(qū)別的意義,對于基本數(shù)據(jù)類型,怎么拷都是“深拷貝”。

淺拷貝就不說了,=就是淺拷貝,那么如何實(shí)現(xiàn)深拷貝呢?
對于ObjectArray兩種類型,我們分別舉例:

Object

首先是assign(),看代碼:

let obj = {name:"hx",age:18};
let copyObj = Object.assign({},obj);
copyObj.name = "H.Lucas";
console.log(obj);
// {name:"hx", age:18} 

Emm,貌似是深拷貝哈,那要是二維對象呢?

let obj = {name:"zj",attr:{age:18, nickname:"Z.Crystal"}}
let copyObj = Object.assign({},obj);
copyObj.attr.nickname = "erni";
console.log(obj);
// {name:"zj",attr:{age:18, nickname:"erni"}}

好吧,翻車了,看來assign只能實(shí)現(xiàn)一維對象的深拷貝。

然后是擴(kuò)展運(yùn)算符...,看代碼:

let obj = {name:"hx",age:18};
let copyObj = {...obj};
copyObj.name = "H.Lucas";
console.log(obj);
// {name:"hx", age:18} 

嗯,深拷貝哈,也來個(gè)二維對象試試:

let obj = {name:"zj",attr:{age:18, nickname:"Z.Crystal"}}
let copyObj = {...obj};
copyObj.attr.nickname = "erni";
console.log(obj);
// {name:"zj",attr:{age:18, nickname:"erni"}}

好吧,也炸了,看來都實(shí)現(xiàn)不了多維對象的深拷貝。

不過這里還是推崇一下...,為什么?看兩段代碼:

let obj1 = {a:1,b:2}
let obj2 = {b:3,c:4}
// 構(gòu)建一個(gè)新對象obj,值是obj1和obj2的集合
let obj = Object.assign(obj1,obj2)
obj.b = 100
console.log(obj1)
console.log(obj2)
// {a: 1, b: 100, c: 4}
// {b: 3, c: 4}
let obj1 = {a:1,b:2}
let obj2 = {b:3,c:4}
// 構(gòu)建一個(gè)新對象obj,值是obj1和obj2的集合
let obj = {...obj1,...obj2}
obj.b = 100
console.log(obj1)
console.log(obj2)
// {a: 1, b: 2}
// {b: 3, c: 4}

在第一段代碼中,執(zhí)行完Object.assign()時(shí),obj1已經(jīng)改變了,而且改變組合出來的obj時(shí),obj1還會再改變。實(shí)際上我只想組合出一個(gè)完全獨(dú)立的obj來,可以肆意改變它,而不影響原始數(shù)據(jù)(想一下純函數(shù)的實(shí)現(xiàn),以及Redux等)。

Array

Emm,數(shù)組拷貝能想到哪些?
slice(),concat(),Array.from()...
這里就不一個(gè)一個(gè)試了,先給出結(jié)論吧:
都只能實(shí)現(xiàn)一維數(shù)組的深拷貝

看個(gè)例子:

let arr1 = [1, 2], arr2 = [...arr1];
console.log(arr1); // [1, 2]
console.log(arr2); // [1, 2]
arr2[0] = 3;
console.log(arr1); // [1, 2]
console.log(arr2); // [3, 2]

let arr3 = [1, 2, [3, 4]], arr4 = [...arr3];
console.log(arr3); // [1, 2, [3, 4]]
console.log(arr4); // [1, 2, [3, 4]]
arr4[2][1] = 5; 
console.log(arr3); // [1, 2, [3, 5]]
console.log(arr4); // [1, 2, [3, 5]]

好吧,那js里到底有沒有不限條件的深拷貝方法呢?看下這個(gè):

let obj1 = {x:1, y:{z:1}};
let obj2 = JSON.parse(JSON.stringify(obj1));
console.log(obj2)
// {x:1, y:{z:1}}

// 改一下obj2,看看會不會影響obj1
obj2.y.z = 2;

console.log(obj1)
// {x:1, y:{z:1}}
// 可以,obj1沒有受到obj2的影響

簡單粗暴吧?不過JSON.parse(JSON.stringify())也并不是萬能的,比如對象的屬性是undefined,function()時(shí):

let obj1 = {
  x: 1,
  y: undefined,
  z: () => console.log("lalala")
};

let obj2 = JSON.parse(JSON.stringify(obj1));

console.log(obj2);
// {x: 1}
// 源對象的屬性y和z都丟失了,更別說深拷貝了

那數(shù)組呢?有沒有不限條件的深拷貝方法,哪怕有個(gè)類似的簡單粗暴的不完全體也行啊。
據(jù)了解只有一種方法,建一個(gè)空數(shù)組,然后一級一級遍歷原數(shù)組并填充到里面吧。

Summary

JavaScript有兩種數(shù)據(jù)類型:基本數(shù)據(jù)類型引用數(shù)據(jù)類型

基本數(shù)據(jù)類型:String,Number,Boolean,Undefined,Null,Symbol

引用數(shù)據(jù)類型:Object,Array,F(xiàn)unction

JavaScript不允許直接訪問內(nèi)存中的位置,因此我們操作的只是對象引用,而不是實(shí)際的對象;

深拷貝淺拷貝是針對引用數(shù)據(jù)類型而言的;

JavaScript暫時(shí)還沒有實(shí)現(xiàn)多維數(shù)組/對象深拷貝的內(nèi)置方法(還是說,有,但是我不知道。。)

對了,補(bǔ)充一個(gè)知識點(diǎn):
有人說,我家=也可以實(shí)現(xiàn)一級深拷貝啊,你看:

let arr1 = {a:1,b:2};
arr2 = arr1;
arr2 = {a:0,b:1};
console.log(arr2); // {a:0, b:2}
console.log(arr1); // {a:1, b:2}

額。。不帶你這么玩的。。
arr2 = {a:0,b:1}; vs. arr2.a = 0;
這兩種操作可不是一碼事。。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/104034.html

相關(guān)文章

  • javascript拷貝VS拷貝

    摘要:深拷貝淺拷貝本文主要對深拷貝淺拷貝的解釋及實(shí)現(xiàn)做一下簡單記錄。之所以會有深拷貝與淺拷貝之分,是因?yàn)椴煌瑪?shù)據(jù)類型的數(shù)據(jù)在內(nèi)存中的存儲區(qū)域不一樣。但注意,只能做一層屬性的淺拷貝。 深拷貝VS淺拷貝 本文主要對深拷貝&淺拷貝的解釋及實(shí)現(xiàn)做一下簡單記錄。原文鏈接,歡迎star。 之所以會有深拷貝與淺拷貝之分,是因?yàn)椴煌瑪?shù)據(jù)類型的數(shù)據(jù)在內(nèi)存中的存儲區(qū)域不一樣。 堆和棧是計(jì)算機(jī)中劃分出來用來存儲的...

    Nekron 評論0 收藏0
  • 拷貝 vs 拷貝

    摘要:那么如何切斷和之間的關(guān)系呢,可以拷貝一份的數(shù)據(jù),根據(jù)拷貝的層級不同可以分為淺拷貝和深拷貝,淺拷貝就是只進(jìn)行一層拷貝,深拷貝就是無限層級拷貝。 深拷貝 vs 淺拷貝 深拷貝和淺拷貝都是針對的引用類型,JS中的變量類型分為值類型(基本類型)和引用類型;對值類型進(jìn)行復(fù)制操作會對值進(jìn)行一份拷貝,而對引用類型賦值,則會進(jìn)行地址的拷貝,最終兩個(gè)變量指向同一份數(shù)據(jù)。 // 基本類型 var a = ...

    sugarmo 評論0 收藏0
  • 拷貝

    摘要:深復(fù)制實(shí)現(xiàn)代碼如下第一種方法通過遞歸解析解決第二種方法通過解析解決作者六師兄鏈接原生深拷貝的實(shí)現(xiàn)處理未輸入新對象的情況通過方法構(gòu)造新的對象 深淺拷貝針對的是 對象類型,如果是字符串的數(shù)組用[...arr],還是不會影響 要區(qū)分針對數(shù)組的深淺拷貝(默認(rèn)情況為里面沒有對象的數(shù)組),與針對對象的深淺拷貝 JavaScript數(shù)組深拷貝和淺拷貝的兩種方法 let a1 = [1, 2]; ...

    Karrdy 評論0 收藏0
  • 拷貝拷貝

    摘要:二淺拷貝與深拷貝深拷貝和淺拷貝是只針對和這樣的引用數(shù)據(jù)類型的。淺拷貝是按位拷貝對象,它會創(chuàng)建一個(gè)新對象,這個(gè)對象有著原始對象屬性值的一份精確拷貝。對于字符串?dāng)?shù)字及布爾值來說不是或者對象,會拷貝這些值到新的數(shù)組里。 一、數(shù)據(jù)類型 數(shù)據(jù)分為基本數(shù)據(jù)類型(String, Number, Boolean, Null, Undefined,Symbol)和對象數(shù)據(jù)類型。 基本數(shù)據(jù)類型的特點(diǎn):直...

    hzc 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<