【JavaScript】聊一聊js中的淺拷貝與深拷貝與手寫實(shí)現(xiàn)
前言
什么是深拷貝與淺拷貝?深拷貝與淺拷貝是js中處理對(duì)象或數(shù)據(jù)復(fù)制操作的兩種方式。?在聊深淺拷貝之前咱得了解一下js中的兩種數(shù)據(jù)類型:
基本數(shù)據(jù)類型(6種)
String、Number、Object、Boolean、null、undefined、symbol(ES6+)
引用數(shù)據(jù)類型
Object(function、Array、正則表達(dá)式等皆是對(duì)象)
- 數(shù)據(jù)的存儲(chǔ)方式是什么?
基本數(shù)據(jù): 基本數(shù)據(jù)類型是存放在棧中的簡(jiǎn)單數(shù)據(jù)段,它們是直接按值存放的,所以可以直接按值訪問
引用類型: 引用類型是存放在堆內(nèi)存中的對(duì)象,保存的在棧內(nèi)存中的一個(gè)指針,保存的是棧內(nèi)存中對(duì)象在堆內(nèi)存中的引用地址。通過這個(gè)引用地址可以快速查找到保存中堆內(nèi)存中的對(duì)象。
1.淺拷貝
1.1 什么是淺拷貝
淺拷貝,指的是創(chuàng)建新的數(shù)據(jù),這個(gè)數(shù)據(jù)有著原始數(shù)據(jù)屬性值的一份精確拷貝。如果屬性是基本類型,拷貝的就是基本類型的值。如果屬性是引用類型,拷貝的就是內(nèi)存地址即淺拷貝是拷貝一層,深層次的引用類型則共享內(nèi)存地址。
- 下面用一張圖來解釋一下淺拷貝

1.2 淺拷貝實(shí)現(xiàn)方法
1.2.1 assign
var obj = {
age: 18,
person: {
name1: 'fx',
name2: 'xka'
},
list:['hhh','666'],
love: function () {
console.log('嘿嘿')
}
}
var newObj = Object.assign({}, obj);
//因?yàn)槭菧\拷貝,所以只拷貝了基本類型的,引用類型還是共享內(nèi)存地址的,即改變obj的應(yīng)用類型的內(nèi)容,newObj里面的引用類型的值也隨之改變
obj.person.name1='xxx'
obj.list[0]='xxx'
console.log(newObj.person.name1) //xxx
1.2.2 slice
const fxArr = ["One", {
name: "Two",
age: 20
}, "Three"]
const fxArrs = fxArr.slice(0,)
fxArr[1].name = "four";
console.log(fxArrs[1].name) //four
1.2.3 concat
const fxArr = ["One", {
name: "Two",
age: 20
}, "Three"]
const fxArrs = fxArr.concat()
fxArr[1].name = "four";
console.log(fxArrs[1].name) //four
1.2.4 拓展運(yùn)算符
const fxArr = ["One", {
name: "Two",
age: 20
}, "Three"]
const fxArrs = [...fxArr]
fxArr[1].name = "four";
console.log(fxArrs[1].name) //four
2.深拷貝
2.1 什么是深拷貝
深拷貝開辟一個(gè)新的棧,兩個(gè)對(duì)象屬完成相同,但是對(duì)應(yīng)兩個(gè)不同的地址,修改一個(gè)對(duì)象的屬性,不會(huì)改變另一個(gè)對(duì)象的屬性
- 下面用一張圖來解釋一下深拷貝

2.2 淺拷貝實(shí)現(xiàn)方法
2.2.1 JSON.parse(常用)
var obj = {
age: 18,
person: {
name1: 'fx',
name2: 'xka'
},
list:['hhh','666'],
love: function () {
console.log('嘿嘿')
}
}
const obj2=JSON.parse(JSON.stringify(obj));
obj.person.name1='6666'
console.log(obj2.person.name1) //fx
- 我常用的基本就是JSON.parse了,然而其他的,之前聽過的lodash的cloneDeep,jq的extend我都沒使用過。
- 但是適用JSON.parse會(huì)有一個(gè)缺點(diǎn),就是處理的數(shù)據(jù)里面有undefined、function、symbol會(huì)被忽略,但是這也是一個(gè)優(yōu)點(diǎn),可以利用其特性將undefined等數(shù)據(jù)排除,拿到干凈的數(shù)據(jù)。還有一個(gè)缺點(diǎn)就是在處理的數(shù)據(jù)比較大的話,還有性能問題。
3.手寫實(shí)現(xiàn)深淺拷貝
3.1 淺拷貝
function clone(object){
const newObj={}
for(let proto in object){
if(object.hasOwnProperty(proto)){
newObj[proto]= object[proto]
}
}
return newObj
}
var obj = {
age: 18,
person: {
name1: 'fx',
name2: 'xka'
},
list:['hhh','666'],
love: function () {
console.log('嘿嘿')
}
}
const obj1=clone(obj)
console.log(obj)
console.log(obj1)
3.2 深拷貝
// 手寫深拷貝
function deepClone(obj, hash = new WeakMap()) {
// 數(shù)據(jù)過濾
if (obj === null) return obj; // 如果是null或者undefined我就不進(jìn)行拷貝操作
if (obj instanceof Date) return new Date(obj);// 如果傳入的對(duì)象是日期對(duì)象,使用 new Date() 創(chuàng)建一個(gè)新的日期對(duì)象并返回
if (obj instanceof RegExp) return new RegExp(obj);// 如果傳入的對(duì)象是正則表達(dá)式對(duì)象,使用 new RegExp() 創(chuàng)建一個(gè)新的正則表達(dá)式對(duì)象并返回
// 如果傳入的對(duì)象不是普通對(duì)象(即不是對(duì)象類型)或普通的值 如果是函數(shù)的話就不需要深拷貝
// 因?yàn)榭截惖闹恍枰紤]是否為對(duì)象,所以只需要判斷obj是否為對(duì)象類型即可,因?yàn)閚ull或者undefined在上面已經(jīng)先過濾掉了,此時(shí)就只剩下基本數(shù)據(jù)類型和函數(shù)了
if (typeof obj !== "object") return obj;
// 來到此處的話就只剩下對(duì)象了,就要進(jìn)行深拷貝
if (hash.get(obj)) return hash.get(obj);
// 深拷貝
// 創(chuàng)建一個(gè)新對(duì)象,這個(gè)新對(duì)象和obj對(duì)象類型相同
// 找到的是所屬類原型上的constructor屬性,而原型上的constructor指向的是當(dāng)前類本身
let cloneObj = new obj.constructor();
hash.set(obj, cloneObj);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 實(shí)現(xiàn)一個(gè)遞歸拷貝
cloneObj[key] = deepClone(obj[key], hash);
}
}
return cloneObj;
}
var obj = {
age: 18,
person: {
name1: 'fx',
name2: 'xka'
},
list:['hhh','666'],
love: function () {
console.log('嘿嘿')
}
}
const obj2 = deepClone(obj) // 深拷貝
const obj3 = Object.assign({}, obj) // 淺拷貝
const obj4 = clone(obj) // 淺拷貝
obj.person.name1 = 'hhh';
//因?yàn)槭巧羁截悾琽bj2中的引用類型新開辟了一個(gè)內(nèi)存地址,所以obj的person改變obj2不受影響
console.log(obj2.person.name1) //fx
//因?yàn)槭菧\拷貝,obj3、obj4中的引用類型與obj中的引用類型共享內(nèi)存地址,所以obj的person改變obj3、obj4皆受影響
console.log(obj3.person.name1) //hhh
console.log(obj4.person.name1) //hhh
上述為個(gè)人學(xué)習(xí)整理內(nèi)容,水平有限,如有錯(cuò)誤之處,望各位園友不吝賜教!如果覺得不錯(cuò),請(qǐng)點(diǎn)擊推薦和關(guān)注!謝謝~??????? [鮮花][鮮花][鮮花]

浙公網(wǎng)安備 33010602011771號(hào)