大家好,我是小逗号,初次来到这里,多多关照,希望我这次作品对于大家认识了解拷贝有一定的帮助。
今天我们一起来了解深拷贝与浅拷贝。
- 在我我们的JS分为两大类型:
-
基本类型:我们常见的数字,字符串,布尔等都属于基本数据类型,这些数据类型大小保存在栈当中。
-
引用类型:我们常见的数组,对象都属于引用数据类型,保存在堆内存当中,而堆内存则是储存地址。
- 首先我们来理解深拷贝与浅拷贝的概念:
- 浅拷贝:只复制引用,会进行彼此影响。
- 深拷贝:完全拷贝出来一个新的对象,开辟新的空间。修改拷贝对象源对象不会受到影响。
我们来看一下日常业务中拷贝的方法
浅拷贝的方法
- 赋值的方法 “=“ 我们这种的拷贝类型拷贝拷贝基本类型的时候是深拷贝,当我们拷贝引用的时候就变成了浅拷贝
var arr1 = ["刘备", "张飞", "关羽"];
var arr2 = arr1;
arr2.push("赵云");
console.log(arr1); // ["刘备", "张飞", "关羽", "赵云"]
console.log(arr2); // ["刘备", "张飞", "关羽", "赵云"]
浅层深拷贝的方法
- 赋值的方法 “=“
var a = "张飞";
var b = a;
a = "关羽";
console.log(a); // 关羽
console.log(b); // 张飞
-
Es6当中的扩展运算符拷贝方法
[...]
var arr = ["诸葛亮", "鲁肃", "司马懿"]
let arr1 = [...arr]
arr.push("曹操")
console.log(arr); // ["诸葛亮", "鲁肃", "司马懿", "曹操"]
console.log(arr1); // ["诸葛亮", "鲁肃", "司马懿"]
{...}
let obj = { name: "张飞" }
let obj2 = {...obj }
obj.age = 18;
console.log(obj); // {name: 'Corey', age: 18}
console.log(obj2); // {name: 'Corey'}
- 利用数组对象的方法进行拷贝
Array.slice()
var arr = ["诸葛亮", "鲁肃", "司马懿"]
let arr1 = arr.slice()
arr.push("曹操")
console.log(arr); // ["诸葛亮", "鲁肃", "司马懿", "曹操"]
console.log(arr1); // ["诸葛亮", "鲁肃", "司马懿"]
Array.concat()
var arr = ["诸葛亮", "鲁肃", "司马懿"]
let arr1 = arr.concat()
arr.push("曹操")
console.log(arr); // ["诸葛亮", "鲁肃", "司马懿", "曹操"]
console.log(arr1); // ["诸葛亮", "鲁肃", "司马懿"]
Array.from()
var arr = ["诸葛亮", "鲁肃", "司马懿"]
let arr1 = Array.from(arr, item => item)
arr.push("曹操")
console.log(arr); // ["诸葛亮", "鲁肃", "司马懿", "曹操"]
console.log(arr1); // ["诸葛亮", "鲁肃", "司马懿"]
Object.assign()
let obj = {name: "张飞"}
let obj2 = {}
Object.assign(obj2, obj);
// let obj2 = Object.assign({}, obj);
obj.age = 18;
console.log(obj); // {name: 'Corey', age: 18}
console.log(obj2); // {name: 'Corey'}
通过以上的方法我们得出结论,以上都是浅拷贝。 以下我们来看一下深拷贝。
深层深拷贝的方法
- 使用JSON.parse(JSON.stringify())进行深拷贝
var arr = [{id: "1",name: "张三" }, [1, 2, 3, 4, 5], function(x) { console.log(x);} ]
let arr1 = JSON.parse(JSON.stringify(arr));
arr1.push("曹操")
console.log(arr); // [{…}, Array(5), null]
console.log(arr1); //[{…}, Array(5), ƒ, "曹操"]
// 很明显没有因为arr1的改变而影响arr,是深拷贝
// 现在我们来调用里面的方法试一试
arr1[2](10) // Uncaught TypeError: arr1[2] is not a functionat demo4.html: 155
// JSON.parse(JSON.stringify()) 这种方法只能拷贝80%,是不能拷贝方法的
- 递归拷贝
var arr = [{id: "1",name: "张三" }, [1, 2, 3, 4, 5], function(x) {console.log(x);}]
// 手写递归函数
function Clone(obj) {
const tar = obj.constructor === Array ? [] : {}
for (let keys in obj) {
if (obj.hasOwnProperty(keys)) {
if (obj[keys] && typeof obj[keys] === "object") {
tar[keys] = obj[keys].constructor === Array ? [] : {}
tar[keys] = Clone(obj[keys])
} else {
tar[keys] = obj[keys]
}
}
}
return tar
}
const Arr = Clone(arr)
Arr[2](10) // 10
// 返回了一个10这种手写递归拷贝是可取的哦
通过这两个方法我们得出以下结论:
- JSON.parse(JSON.stringify())可以进行深拷贝,但是不会拷贝里面的方法。
- 递归方法进行开辟新的存储地址这种拷贝,可以拷贝里面的方法。