前段时间开发项目中碰到了深浅拷贝的问题,现在给自己写个总结(^▽^)。
简单来说,假设a是引用数据类型,b复制了a,改变a以后,b也跟着改变,就是浅拷贝,b不跟着改变,就是深拷贝。如果要了解具体的运行机制,这篇文章已经讲的很详细了,我也是参考这篇文章写得(^▽^):www.cnblogs.com/echolun/p/7…
什么是引用数据类型?
数据类型分为:基本数据类型与引用数据类型
基本数据类型:number,string,boolean,null,undefined五类
引用数据类型:Object类:{a:1},数组:[1,2,3],以及函数等
一.基本数据类型
定义:名、值存储在栈内存中
例子:
var a=1;var b=a;
a=2; //a=2,b=1
复制代码
注:这里b复制了a,改变a以后,b不跟着改变,但这不是深拷贝。深浅拷贝只是针对较为复杂的引用数据类型来说的。
二.引用数据类型
定义:名存在栈内存中,值存在于堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值。
浅拷贝
例子:
var object={a:1,b:2};var copy=object;
object.a=2; //object={a:2,b:2},copy={a:2,b:2}
复制代码
这里改变了a的值,b也跟着改变,就是浅拷贝。
还有一种是半独立状态的浅拷贝,即运行机制还是一样的,只是拷贝了对象实例的属性。
例子:
var a={name:'jack'};var b={...a};
a.name='tom' // a={name:'tom'} , b={name:'jack'}
复制代码
等同于
var a={name:'jack'};var b=Object.assign({}, a);
a.name='tom' // a={name:'tom'} , b={name:'jack'}
复制代码
这里通过es6的解构把a拆开赋值给b,这样改变了a的值以后,b还是原来的值,这种就是半独立状态的浅拷贝。
深拷贝
那要怎么实现深拷贝呢?
1.借用JSON对象的parse和stringify方法
let a=[0,1,[2,3],4]
let aClone=JSON.parse(JSON.stringify(a))
a[0]=8;a[2][0]=8; // a=[8,1,[8,3],4],aClone=[0,1,[2,3],4]
复制代码
2.通过递归去复制所有层级属性
deepClone (obj) {
// 定义需要拷贝的新元素,并判断当前元素是不是数组
let objClone = Array.isArray(obj) ? [] : {}
if (obj && typeof obj === 'object') {
// 判断当前元素是不是对象 or 数组
for (let key in obj) {
// 判断obj子元素是否为对象or数组,如果是,递归复制,如果不是,简单复制
objClone[key] =
typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key]
}
}
return objClone
},
let a = [0,1,2,3];
let b = deepClone(a)
a[0]=8; // a=[8,1,2,3],b=[0,1,2,3]
复制代码
3.依赖JQ库的extend方法
$.extend ( [ deep ], target, object1 [ , objectN ] )
复制代码
deep: 可选。 Boolean类型,指示是否深度合并对象,默认为false。如果该值为true,且多个对象的某个同名属性也都是对象,则该"属性对象"的属性也将进行合并。
target: Object/Array类型的目标对象,其他对象的成员属性将被附加到该对象上。
object1: 可选。 Object/Array类型,第一个被合并的对象。
objectN: 可选。 Object/Array类型,第N个被合并的对象。
let a = {name: 'Jack', age: 13}
let b = {address: 'China'}
let c = JQ.extend(true, [], a, b)
a.name = 'Tom'
console.log(c); // {name: 'Jack', age: 13, address: 'China'}
复制代码
let a = [0, 1, [2, 3], 4]
let b = [123, 456]
let c = JQ.extend(true, [], a, b)
a[2][0] = 8
console.log(c); // [123,456,[2,3],4]
复制代码
4.SessionStorage/LocalStorage
这种方法一般用于全局变量或者刷新时也需要保存的数据,但如果需要保存的数据是object或array类型的,就需要用到JSON.parse和JSON.stringify,因为SessionStorage/LocalStorage无法单独获取到存储的数据类型是object或array的。
let arr=[1,2,3]
sessionStorage.setItem('arr', JSON.stringify(arr))
复制代码
JSON.parse(sessionStorage.getItem('arr')); // [1,2,3]
复制代码