前言
本文是整理的淺拷貝和深拷貝中涉及的知識點,在工作中是非常重要的,在面試中也是必考的,希望對小夥伴們有所幫助!
為什麼會產生深淺拷貝?
首先我們要知道一個流程
1,物件屬於引用型別的,以後瀏覽器會為其開闢一個新的記憶體空間,併為它分配一個16進位制的地址
2,按照一定的順序,把物件的鍵值對儲存到記憶體空間
3,把開闢的記憶體地址賦值給變數(或事件),以後變數就通過地址找到記憶體空間,然後進行操作
基本資料型別和引用資料型別
資料分為基本資料型別和引用資料型別
基本資料型別
String、Number、Boolean、Null、Undefined、Symbol
複製程式碼
基本資料型別是直接儲存在棧中的資料
let str1 = '123';
str2 = str1;
str2 = '456';
console.log(str1); // '123'
console.log(str2); // '456'
複製程式碼
形象舉例:
我之前買了一雙鞋子,我現在又買了一雙,某一雙壞了不會影響到另外一雙
引用資料型別
Array、Object
複製程式碼
引用資料型別儲存的是該物件在棧中引用,真實的資料儲存在記憶體中
let arr1 =[1,2,3,4,5,6];
arr2 = arr1;
arr2.pop();
console.log(arr1);//[ 1, 2, 3, 4, 5 ]
console.log(arr2);//[ 1, 2, 3, 4, 5 ]
複製程式碼
形象舉例:
在大草原上,有一些羊吃了腐爛的草得病死了。草原還是草原,但是內部的草變少了;羊群還是羊群,但是內部的羊變少了
深拷貝和淺拷貝的概念
淺拷貝:
僅僅複製物件的引用,而不是物件本身
複製程式碼
深拷貝:
把複製的物件所引用的全部物件都複製一遍
複製程式碼
深拷貝和淺拷貝的區別
~ | 和原資料是否指向同一物件 | 第一層資料為基本資料型別 | 原資料中包含子物件 |
---|---|---|---|
賦值 | 是 | 改變會使資料一同改變 | 改變會使原資料一同改變 |
淺拷貝 | 否 | 改變不會使原資料一同改變 | 改變會使資料一同改變 |
深拷貝 | 否 | 改變不會使原資料一同改變 | 改變不會使原資料一同改變 |
淺拷貝
通用迴圈
const arr1 = [1, 2, ['ming', 'abc'], 5];
const shallowClone = (arr) => {
const dst = [];
for (let prop in arr) {
if (arr.hasOwnProperty(prop)) {
dst[prop] = arr[prop];
}
}
return dst;
}
const arr2 = shallowClone(arr1);
arr2[2].push('wuhan');
arr2[3] = 5;
console.log(arr1);
console.log(arr2);
複製程式碼
執行結果:
object.assign()
- Object.assign()方法可以把任意多個的源物件自身的可列舉屬性拷貝給目標物件,然後返回目標物件
- Object.assign()進行的是淺拷貝,拷貝的是物件的屬性的引用,而不是物件本身
const obj1 = {
username:'ming',
skill:{
play:['backetball','game'],
rend: 'book',
},
girlfriends:['xiaomi','xiaohong','xiaolan'],
};
const obj2 = Object.assign({},obj1);
obj2.username = 'memg';//修改基本型別
obj2.skill.read = 'e-mail';//修改二層基本型別
obj2.skill.play = ['footbool'];//修改二層引用型別
obj2.girlfriend = ['xiaoming'];
console.log(obj1);
console.log(obj2);
複製程式碼
執行結果:
Array.prototype.concat()
concat()是陣列的一個內建方法,使用者合併兩個或者多個陣列
這個方法不會改變現有陣列,而是返回一個新陣列
const arr1 = [1,{username: 'ming',},];
let arr2 = arr1.concat();
arr1[0] = 2;
arr1[1].username = 'meng';
console.log(arr1);
console.log(arr2);
複製程式碼
執行結果:
Array.prototype.slice()
slice()也是陣列的一個內建方法,該方法會返回一個新的物件
slice()不會改變原陣列
const arr1 = [1,{username:'ming',},];
let arr2 = arr1.slice();
arr2[0] = 2;
arr2[1].username = 'meng'
console.log(arr1);
console.log(arr2);
複製程式碼
執行結果:
obj展開運算子
展開運算子是ES6中新提出來的一種運算子
在拷貝陣列、物件以及拼接陣列等方面都可以使用
這步我們也可以嘗試下使用const obj2 = {...obj1}的形式進行淺拷貝
//拷貝陣列
const arr1 = [1, 2, 3];
const arr2 = [...arr1]; // like arr.slice()
arr2.push(8);
console.log(arr1); // [ 1, 2, 3 ]
console.log(arr2); // [ 1, 2, 3, 8 ]
//拷貝物件
const obj1 = {
name: 'ming',
arr1: ['9', '7', '6'],
obj: {
name: 'meng',
arr2: ['7', '8', '9'],
},
};
const obj2 = {...obj1};// like arr.slice()
obj2.name = 'ming2';
obj2.arr1 = ['null'];
obj2.obj.name = 'meng2';
obj2.obj.arr2 = ['null'];
console.log(obj1);
console.log(obj2);
複製程式碼
執行結果:
深拷貝
手動遞迴
function deepClone (sourceObj, targetObj) {
let cloneObj = targetObj || {}
if(!sourceObj || typeof sourceObj !== "object" || sourceObj.length === undefined){
return sourceObj
}
if(sourceObj instanceof Array){
cloneObj = sourceObj.concat()
} else {
for(let i in sourceObj){
if (typeof sourceObj[i] === 'object') {
cloneObj[i] = deepClone(sourceObj[i], {})
} else {
cloneObj[i] = sourceObj[i]
}
}
}
return cloneObj
}
let sourceObj = {
a: 1,
b: {
a: 1
},
c: {
a: 1,
b: {
a: 1
}
},
d: function() {
console.log('hello world')
},
e: [1, 2, 3]
}
let targetObj = deepClone(sourceObj, {})
targetObj.c.b.a = 9
console.log(sourceObj)
console.log(targetObj)
複製程式碼
執行結果:
Json.parse(Json.Stringify())
JSON.stringify():把一個js物件序列化為一個JSON字串
JSON.parse():把JSON字串反序列化為一個js物件
const arr9 = [
1,
{
username:'ming',
},
];
let arr10 = JSON.parse(JSON.stringify(arr9));
arr10[0]=2;
arr10[1].username='meng';
console.log(arr9);
console.log(arr10);
複製程式碼
執行結果:
let obj = {
name: 'ming',
age: 20,
friend: {
name: 'ming1',
age: 19
}
};
let copyObj = JSON.parse(JSON.stringify(obj));
obj.name = 'meng';
obj.friend.name = 'meng1';
console.log(obj);
console.log(copyObj);
複製程式碼
執行結果:
函式庫Lodash
Lodash作為JavaScript函式庫/工具庫,它裡面有非常好用的封裝好的功能
var _= require('lodash');
const obj1 = [
1,
'Hello!',
{ name:'ming1' },
[
{
name:'meng1',
}
],
]
const obj2 = _.cloneDeep(obj1);
obj2[0] = 2;
obj2[1] = 'Hi!';
obj2[2].name = 'ming2'
obj2[3][0].name = 'meng2';
console.log(obj1);
console.log(obj2);
複製程式碼
執行結果:
最後
如果本文對你有幫助得話,給本文點個贊❤️❤️❤️
歡迎大家加入,一起學習前端,共同進步!