賦值,淺拷貝,深拷貝的區別

2021-10-06 15:48:25 字數 4469 閱讀 3414

一、賦值(copy)

賦值是將某一數值或物件賦給某個變數的過程,分為下面 2 部分:

基本資料型別:賦值,賦值之後兩個變數互不影響

引用資料型別:賦址,兩個變數具有相同的引用,指向同乙個物件,相互之間有影響

let a =10;

let b = a;

console.

log(a)

;//10

console.

log(b)

;//100

a =100

;console.

log(a)

;//100

console.

log(b)

;//10

對基本型別進行賦值操作,兩個變數互不影響。

let a =

;let b = a;

console.

log(a);//

console.

log(b);//

a.age =19;

console.

log(a);//

console.

log(b)

;//

對引用型別進行賦址操作,兩個變數指向同乙個物件,改變變數 a 之後會影響變數 b。

通常在開發中並不希望改變變數 a 之後會影響到變數 b,這時就需要用到淺拷貝和深拷貝。

二、淺拷貝(shallow copy)

1、什麼是淺拷貝

建立乙個新物件,這個物件有著原始物件屬性值的乙份精確拷貝。如果屬性是基本型別,拷貝的就是基本型別的值,如果屬性是引用型別,拷貝的就是記憶體位址 ,所以如果其中乙個物件改變了這個位址,就會影響到另乙個物件。簡單來說可以理解為淺拷貝只解決了第一層的問題,拷貝第一層的基本型別值,以及第一層的引用型別位址。

2.下面說說淺拷貝的幾個方法:

一.object.assign(用於將所有可列舉屬性的值從乙個或多個源物件複製到目標物件。它將返回目標物件)

object.assign方法實行的是淺拷貝,而不是深拷貝。也就是說,如果源物件某個屬性的值是物件,那麼目標物件拷貝得到的是這個物件的引用

let a =

;let b = object.

assign

(,a)

;console.

log(a)

;// ;

console.

log(b)

;// ;

a.sports.

push

("basketball"

)console.

log(a)

;// ;

console.

log(b)

;// ;

上面**改變物件 a 之後,物件 b 的基本屬性保持不變。但是當改變物件 a 中的物件 sports 時,物件 b 也發生了變化。

二.array.prototype.slice()

返回乙個新的陣列物件,這一物件是原陣列的淺拷貝。原始陣列不會被改變。

let a =

["1"

,"2",]

;let b = a.

slice(2

);console.

log(b)

;// ;b[0

].age =

"19"

console.

log(a)

;// ["1","20",];

console.

log(b)

;// ;

實際開發中我們可能經常會碰到,對乙個陣列進行拷貝,然後對拷貝的陣列進行操作,其實是會影響到原陣列的,這點我們需要記住,array.prototype.slice()是淺拷貝!

三、深拷貝(deep copy)

1、什麼是深拷貝

深拷貝會拷貝所有的屬性,並拷貝屬性指向的動態分配的記憶體。當物件和它所引用的物件一起拷貝時即發生深拷貝。深拷貝相比於淺拷貝速度較慢並且花銷較大。拷貝前後兩個物件互不影響。

2.下面說說淺拷貝的幾個方法:

一.json.parse(json.stringify())

let a =

;let b =

json

.parse

(json

.stringify

(a))

;console.

log(a)

;// ;

console.

log(b)

;// ;

a.sports.

push

("basketball"

)console.

log(a)

;// ;

console.

log(b)

;// ;

完全改變變數 a 之後對 b 沒有任何影響,這就是深拷貝。

看下對陣列深拷貝效果如何

let a =

["1"

,"2",]

;let b =

json

.parse

(json

.stringify

(a.slice(2

)));

console.

log(b)

;// ;b[0

].age =

"19"

console.

log(a)

;// ["1","20",];

console.

log(b)

;// ;

對陣列深拷貝之後,改變原陣列不會影響到拷貝之後的陣列。

但是該方法有以下幾個問題。

(1)、會忽略 undefined

(2)、會忽略 symbol

(3)、不能序列化函式

(4)、不能解決迴圈引用的物件

(5)、不能正確處理new date()

(6)、不能處理正則

let a =[}

];console.

log(a)

;// [

// }];

let b =

json

.parse

(json

.stringify

(a))

;

console.

log(b)

;//

undefined、symbol 和函式這三種情況,會直接忽略。

let obj =};

obj.b = obj.c;

obj.c.d = obj.b;

let b =

json

.parse

(json

.stringify

(obj));

console.

log(b)

;// uncaught typeerror: converting circular structure to json

// --> starting at object with constructor 'object'

// --- property 'd' closes the circle

// at json.stringify ()

迴圈引用情況下,會報錯。

let time =

newdate()

;console.

log(time)

//sat may 30 2020 16:35:38 gmt+0800 (中國標準時間)

let time1 =

json

.parse

(json

.stringify

(time));

console.

log(time1)

;

new date 情況下,轉換結果不正確。

let a =

;console.

log(a)

// let b =

json

.parse

(json

.stringify

(a))

;console.

log(b)

;// ,

// }

正則情況下,轉換結果直接是個物件。

除了上面介紹的深拷貝方法,常用的還有jquery.extend()等,有興趣的朋友可以自己去了解下!

四、總結

賦值,如果是引用型別,和原資料是指向同一物件,改變會使原資料一同改變,如果是基本型別,改變不會使原資料一同改變!淺拷貝的話,如果第一層有基本型別,改變基本型別不會影響原資料的基本型別資料,如果還有引用型別,改變引用型別會影響原資料的引用型別資料(淺拷貝只拷貝一層),深拷貝的話,不管是基本型別還是引用型別,怎麼改都不會影響原資料!

淺拷貝 深拷貝和淺賦值 深賦值

include includeusing namespace std class string else 淺拷貝 也就是系統預設的拷貝,可寫可不寫。string const string s 預設的拷貝構造 深拷貝 string const string s string s2 s1 深賦值 str...

賦值 淺拷貝 深拷貝

堆是動態分配記憶體,記憶體大小不一 棧是自動分配相對固定大小的記憶體空間,並由系統自動釋放 基本資料型別值是不可變的,比較是值的比較 基本資料型別,傳值。開闢乙個新的記憶體空間 js 基本資料型別,儲存在 棧 中,記憶體可以及時 引用型別值是可變的,比較是引用的比較,看其引用是否指向同乙個物件 引用...

深拷貝 淺拷貝 賦值

賦值 class teacher class student student s1 new student student s2 s1 s1 s2,指向的記憶體區域相同 拷貝 class teacher class student implement cloneable student s1 new...