浅拷贝与深拷贝
相关知识
javascript变量包含两种不同数据类型的值:基本类型和引用类型
1、基本类型值指的是简单的数据段,包括es6里面新增的一共是有6种,具体如下:number、string、boolean、null、undefined、symbol。
2、引用类型值指那些可能由多个值构成的对象,只有一种如下:object。
javascript的变量的存储方式:栈(stack)和堆(heap)
栈:自动分配内存空间,系统自动释放,里面存放的是基本类型的值和引用类型的地址
堆:动态分配的内存,大小不定,也不会自动释放。里面存放引用类型的值。
所有在方法中定义的变量都是放在栈内存中的;栈中存储的是基础变量以及一些对象的引用变量,基础变量的值是存储在栈中,而引用变量存储在栈中的是指向堆中的数组或者对象的地址
基本类型与引用类型最大的区别实际就是 传值与传址 的区别
浅拷贝
定义:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。即对象的浅拷贝会对“主”对象进行拷贝,但不会复制主对象里面的对象。”里面的对象“会在原来的对象和它的副本之间共享。
基本数据类型Number(赋值操作)
浅拷贝 传的是地址
//浅拷贝 传的是地址
var arr = [1, 2, 3]
var arr_1 = arr
arr_1.push(4)
console.log(arr);
console.log(arr_1);
深拷贝
定义:深拷贝不仅将原对象的各个属性逐个复制出去,而且将原对象各个属性所包含的对象也依次采用深复制的方法递归复制到新对象上,所以对一个对象的修改并不会影响另一个对象。
数组(注意:该数组只是单纯的数组,如果数组里面嵌套对象,则下面的几种方法都不是深拷贝。)
深拷贝 传的值
数组
法一:for循环
//for循环
var arr_2 = [1, 2, 3]
var arr_3 = []
for (var i = 0; i < arr_2.length; i++) {
arr_3.push(arr_2[i])
}
arr_3.unshift(0)
console.log(arr_2);
console.log(arr_3);
法二: slice
var arr_4 = [1, 2, 3]
var arr_5 = arr_4.slice(0)
arr_5.push(4)
console.log(arr_4);
console.log(arr_5);
法三: concat
//3、concat()
var arr_6 = [1, 2, 3]
var arr_7 = arr_6.concat()
arr_7.shift()
console.log(arr_6);
console.log(arr_7);
方法四、ES6扩展运算符实现数组的深拷贝
var arr1 = [1, 2, 3];
var [...arr2] = arr1;
arr1[0] = 4;
console.log(arr1); //4, 2, 3
console.log(arr2); //1, 2, 3
对象
方法一、使用JSON暴力转换
通过JSON.stringify() 和 JSON.parse() 将对象转为字符串之后在转为对象。
var obj = {name:'123'};
var obj2 = JSON.parse(JSON.stringify(obj))
方法二、 使用拓展运算符+解构赋值
该方法的局限性在于,当值为undefined、function、symbol会在转换过程中被忽略。
var obj = {name:'123',age:13};
var obj2 = {...obj}
方法三、 使用对象的合并,即通过Object.assign()方法
注意:该方法的第一个参数必须是空对象
var obj = {name:'123',age:13};
var obj2 = Object.assign({},obj);
方法四、for in遍历对象
// 对象 (for in)
var obj_1 = {
name: 'name',
age: 18
}
var obj_2 = {}
for (x in obj_1) {
obj_2[x] = obj_1[x]
}
obj_2.name = 'name1'
console.log(obj_1);
console.log(obj_2);
五、利用循环递归
以上四种方法只能进行一层拷贝,即当对象的属性值也是对象时,就无法实现该属性的深拷贝,在这里提供一种利用循环递归进行深拷贝的方法。
var obj = {
name: "123",
sex: { age: "小花" }
};
var newObj = {};
function deepClone(obj, newObj) {
var newObj = newObj || {};
for (let key in obj) {
if (typeof obj[key] == 'object') {
newObj[key] = (obj[key].constructor === Array) ? [] : {}
deepClone(obj[key], newObj[key]);
} else {
newObj[key] = obj[key]
}
}
return newObj;
}
console.log(deepClone(obj, newObj));//{name: "123",sex: {age: '小花'}}