js中的深拷贝和浅拷贝
1. js变量的存储方式
1.1 栈和堆
栈:自动分配内存空间,系统自动释放,里面存放的是基本数据类型的值和引用类型的地址
堆:动态分配的内存,大小不定,也不会自动释放。里面存放引用类型的值
例:
var str1 = 'qwe';
var str2 = str1;
str2 = 'asd';
console.log(str1, str2);//qwe asd
var obj1 = { name: 'obj1' };
var obj2 = obj1;
obj2.name = 'obj2';
console.log(obj1, obj2);
//{name: 'obj2'} {name: 'obj2'}
1.2 基本类型和引用类型的赋值
基本类型:赋值 赋的是真正的值
引用类型:赋值 赋的是引用类型的地址
例:
var num1=10;
var num2=10;
console.log(num==age);//true
var arr=[1,2,3]
var arr2=[1,2,3]
console.log(arr==arr2);//false
2. 浅拷贝和深拷贝
2.1 浅拷贝
传的是地址
2.1.1 数组
var arr1 = [1, 3, 5]
var arr2 = arr1;
arr2.push(7);
console.log(arr1);//[1,3,5,7]
console.log(arr2);//[1,3,5,7]
2.2 深拷贝
传的是值
2.2.1 for循环
var arr3 = [1, 3, 5]
var arr4 = [];
for (var i = 0; i < arr3.length; i++) {
arr4.push(arr3[i]);
}
arr4.unshift(0);//添加
console.log(arr3, arr4);// [1, 3, 5] [0, 1, 3, 5]
2.2.2 slice()
var arr5 = [2, 4, 6];
var arr6 = arr5.slice(0);
arr6.shift();//删除第一个
console.log(arr5, arr6)//[2,4,6] [4,6]
2.2.3 concat()
var arr7 = [5, 6, 7];
var arr8 = arr7.concat();
arr8.pop();//删除最后一个
console.log(arr7, arr8);//[5,6,7] [5,6]
2.2.4 对象
var obj1 = {
name: 'obj1',
age: '20'
}
var obj2 = {};
for (k in obj1) {
obj2[k] = obj1[k];
}
obj2.age = 100;
console.log(obj1, obj2);
//{name: 'obj1', age: '20'} {name: 'obj1', age: 100}
2.2.5 JSON.parse(JSON.stringify())
用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,产生了新的对象,而且对象会开辟新的栈,实现深拷贝
let arr=[1,2,3{username:'ming'}];
let arrSecond=JSON.parse(JSON.stringify(arr));
arrSecond[2].username='hong';
console.log(arr,arrSecond);
// [1, 2, 3, { username: 'ming' }]
//[1, 2, 3, { username: 'hong' }]
但不能处理函数
let arr = [1, 2, { username: "haha" }, function () { }];
let arr2 = JSON.parse(JSON.stringify(arr));
arr2[2].username = 'heihei';
console.log(arr, arr2);
2.2.6 手写递归方法
递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝
var obj = {
id: 1,
name: 'andy',
msg: {age: 18},
color: ['pink', 'red']
};
var o = {};
// 用递归的方式完成深拷贝
// 封装函数
function deepCopy(newobj, oldobj) {
// 遍历oldobj的属性名
for (var k in oldobj) {
// 判断属性属于哪种数据类型
// 1.获取属性值 oldobj[k]
var item = oldobj[k];
// 2.判断是否属于数组(因为数组也属于对象,所以必须先判断数组)
if (item instanceof Array) {
newobj[k] = []; // (1)先给newobj添加一个属性k,同oldobj里的k
deepCopy(newobj[k], item) // (2)再用oldobj[k]赋值给newobj[k]
} else if (item instanceof Object) {
// 3.判断是否属于对象
newobj[k] = {};
deepCopy(newobj[k], item)
} else {
// 4.属于简单数据类型
newobj[k] = item
}
}
}
deepCopy(o, obj)
console.log(o);
2.2.7 函数库
var _ = require('lodash');
var obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);
// false