(琢磨)從深拷貝聯絡到原型鏈和函式繼承

2021-10-10 14:55:43 字數 3608 閱讀 9786

淺拷貝:就是將定義的物件指向目的物件的位址,所以當我們對新建立的物件進行修改時,原來的目標物件也被修改了。(下文中,將只執行了第一層深拷貝化的做法,即沒有完全深拷貝的做法也稱為淺拷貝了。)

深拷貝:就是讓新建立的物件有乙個全新的位址,然後內容和原來的物件一樣。

如果物件內的屬性或者陣列的元素都是值型別,那麼我們無需考慮這一問題(只要實現一層深拷貝就完成了,很簡單),但是當其是引用型別的時候,就需要實現深拷貝來實現資料的隔離了。

let a =

let b =

b['name']=

'bbb'

;console.

log(a)

;console.

log(b)

;

let a =

let b =

object.

assign

(b,a);b[

'name']=

'bbb'

;console.

log(a)

;console.

log(b)

;

slice() 方法可從已有的陣列中返回由選定的元素組成的陣列。兩個引數(start,end),都是可選的,如果不填就是整個複製了。

let arr1 =[1

,2,3

,4,5

]let arr2 =

[...arr1]

let arr3 = arr1.

slice()

let arr4 =

.concat

(arr1)

console

.log

(arr1,arr2,arr3,arr4)

對於深拷貝應該思考乙個問題,之前就反覆在說,引用型別中的棧放的是位址,那麼如果物件中有引用型別的屬性,一次的深拷貝肯定是不夠的。需要對引用型別的屬性也進行深拷貝,如此迴圈直至結束。基於json.stringify將物件先轉成字串,再通過json.parse將字串轉成物件,此時物件中每個層級的堆記憶體都是新開闢的。

let obj =

}let obj2 =

json

.parse

(json

.stringify

(obj)

)console

.log

(obj,obj2)

console

.log

(obj.skills === obj2.skills)

// false

思路:判斷型別+拷貝+迴圈

首先判斷當前的型別,如果是引用型別,那麼遍歷屬性並對每個屬性進行遞迴操作,如果是值型別,那麼不需要進行遞迴,直接返回即可。

判斷型別的方法

object.prototype.tostring.

call

(obj)

.slice(8

,-1)

function

checktype

(target)

function

deepclone

(target)

// 要用乙個新的位址

object.

keys

(target)

.foreach

(item =>

)return result

}let obj =

}let obj2 =

deepclone

(obj)

obj2.skills.run =

'quickly run'

console

.log

(obj,obj2)

一直在思考,原型鏈的繼承是深拷貝還是淺拷貝呢?

先說結論:也是一種淺拷貝,或者說只進行了第一層深拷貝。

首先複習一下原型鏈的一些知識點。

注意區分顯式原型prototype和隱式原型[[prototype]],後者是乙個內部屬性一般看不到。 可以通過__proto__屬性在chrome瀏覽器中使用。

物件的__proto__引用值指向建立這個物件的建構函式的prototype物件

所有prototype物件都是由object建立的,除了object.prototype物件本身

所有建構函式本身都是由function建立的,除了function本身

對於原型鏈的取值很好理解,當前例項中沒有時會沿著原型鏈一直往上尋找。

但是賦值就比較複雜了,是會一直往上尋找值然後修改嗎?

之前的學習中了解到,在使用new的時候,會把新建立例項的[[prototype]](也就是__proto__)和建構函式的prototype進行乙個賦值。那麼這裡就要思考乙個問題,如果是淺拷貝的話,那不是會出現一些問題嗎?各個例項之間的內容就會互相影響了。

這裡必然是有些奇妙之處的。

根據**可見,對於值型別的屬性a中對於原型鏈上屬性的更改並不會影響到b。

這是因為:此時會在原物件上對該屬性進行賦值修改操作,而不是在原型鏈上的這個物件上修改。(如果該屬性存在setter的話也可能對原型鏈上的值進行修改)

那麼可以聯想到,如果是引用型別的話,這個賦值就會導致各個例項互相影響的情況

值型別

class

human

}human.prototype.we =

'human'

let a =

newhuman()

let b =

newhuman()

a.we =

'a'console

.log

(a.we)

// a

console

.log

(b.we)

// human

引用型別

class

human

}human.prototype.we =

let a =

newhuman()

let b =

newhuman()

a.we.name =

'a'console

.log

(a.we)

// console

.log

(b.we)

//

正因為通過原型鏈來獲取屬性會導致例項互相影響的情況,所以我們在繼承中對於屬性使用this呼叫父類的建構函式。對於方法使用原型鏈(但是在乙個例項的原型中新增方法時其他例項以及原先的建構函式也可以通過例項使用方法)。

father.

call

(this

, 引數)

;

明確原型鏈是針對例項的就好了。

c 從淺拷貝和深拷貝到預設拷貝函式

深度拷貝和淺拷貝在c語言中就經常遇到的了,在這裡我簡單描述。一般的賦值操作是深度拷貝 深度拷貝 int a 5 int b a 所謂深度拷貝,即為在堆疊記憶體中新開闢了一塊區域,儲存著拷貝過來的資料。以上述 為例,a和b分別指向記憶體中不同的位址,而兩部分位址中儲存著相同的5。簡單的指標指向,則是淺...

淺拷貝 深拷貝

copy mutablecopy copy 不管是可變的,還是不可變的,結果都是不可變的 mutablecopy 不管是不可變的,還是可變的,結果都是可變的 nsmutablestring str nsmutablestring stringwithformat a nsarray arr1 str...

深拷貝 淺拷貝

c 中物件的複製就如同 轉殖 用乙個已有的物件快速地複製出多個完全相同的物件。一般而言,以下三種情況都會使用到物件的複製 1 建立乙個新物件,並用另乙個同類的已有物件對新物件進行初始化,例如 cpp view plain copy class rect rect rect1 rect rect2 r...