下面了解下什么浅复制【拷贝】和深复制【拷贝】,经过下面的阅读你将了解到:前端
一、什么是浅复制以及使用场景
二、什么是深复制以及使用场景
三、浅复制和深复制有哪些方式
复制代码
1、咱们先来了解下,JavaScript基本知识,基本类型和引用类型es6
基本类型:number、string、boolean、null、undefined 后来es6又增长了一个基本类型symbol,目前基本类型为6个
引用类型:Object、 Function、Array
复制代码
什么是堆【heap】和 栈 【stack】数组
栈:自动分配内存,系统自动释放,里面包含值类型和引用类型的地址【引用对象】
堆:动态分配内存,大小不定,系统不会自动释放,里面存放引用类型的值【实例对象】bash
看个例子:闭包
let a=1;
let b=a;
console.log(a)//1
console.log(b)//1
b=3;
console.log(b)//3
console.log(a)//1
复制代码
从例子得出结论:当值赋值给变量时,解析器肯定是基本类型值仍是引用类型值。基本数据类型,是值访问的,而且能够操做保存在变量中的实际值。基本类型复制的时候,就是在栈中开辟一个新的存储区域用来存储变量。因此其中一个值变化,不会影响另外一个值.
如例子:虽然b=3发生了改变,但a输出结果仍是1,印证上面的结论.app
let obj={name:'zjl',remark:'zjl'};
let anotherObj=obj;
anotherObj.name='lisi'
console.log(obj);//{name:'lisi',remark:'zjl'};
复制代码
从上面的例子中,能够看出一个值发生的改变也影响到了另外一个.
如上:obj的name由zjl变为了lisi,这是为何呢?函数
引用类型值【实例对象】,是存放在堆内存中的对象。与其它语言不一样,JavaScript中,不容许直接访问内存位置及不能直接操做内存空间。实际操做的是对象的引用【指针】,不是实际的对象。ui
补充:对象引用是栈中的地址,复制对象时,至关于在栈中开辟新的一块区域存放这个地址(指针),这个指针指向同一块堆内存位置。因此其中一个指针对象发生改变,另外一个也会发生改变。spa
2、下面就,常见的数组【Array】和对象【Object】,来讨论下深浅复制指针
一、浅复制【拷贝】
//数组浅复制
let arr=[1,2,3,5,8];
let item=[];
for(let i in arr){
item[i]=arr[i];
}
item.push(9);
console.log('arr==>'+arr);//arr==>1,2,3,5,8
console.log('item==>'+item);//item==>1,2,3,5,8,9
//对象浅复制
let obj={name:'zjl',age:'28'};
let list={};
for(let i in obj){
list[i]=obj[i];
}
list['like']='apple';
console.dir('obj===>'+JSON.stringify(obj));
console.dir('list===>'+JSON.stringify(list));
obj===>{"name":"zjl","age":"28"}
list===>{"name":"zjl","age":"28","like":"apple"}
复制代码
以上例子能够看出,数组、对象实现了浅复制.可是上面的代码只能实现一层的拷贝,没法实现深层的拷贝,若是把上面的代码改动下,以下:
//对象浅复制
let obj={name:'zjl',age:'28'};
let list={};
for(let i in obj){
list[i]=obj[i];
}
list['name']='lisi';
console.dir('obj===>'+JSON.stringify(obj));
console.dir('list===>'+JSON.stringify(list));
obj===>{"name":"lisi","age":"28"}
list===>{"name":"lisi","age":"28"}
复制代码
上面的例子,能够看出对象name被改变了.影响了原始的对象值.因引用类型为地址传递,没有开辟新的堆内存,地址指向同一块内存位置,因此改变一个对象另外一个对象也会随之改变。因此没法实现深层次的复制【拷贝】.怎样解决这个问题,咱们须要使用深拷贝【复制】来完成,继续往下看...
二、深复制【拷贝】: 看下面的例子,递归实现深层复制:
var china = {
nation: '中国',
adrress: ['北京', '上海', '广州'],
}
//深复制,要想达到深复制就须要用递归
function deepCopy(o, c) {
var c = c || {}
for (var i in o) {
if (typeof o[i] === 'object') { //要考虑深复制问题了
if (o[i].constructor === Array) {
//这是数组
c[i] = []
} else {
//这是对象
c[i] = {}
}
deepCopy(o[i], c[i])
} else {
c[i] = o[i]
}
}
return c
}
var result = {}
result = deepCopy(china, result);
result.nation = '美国';
console.dir(JSON.stringify(result)); //{"adrress":["北京","上海","广州"],"nation":"美国"}
console.dir(JSON.stringify(china)); //{"adrress":["北京","上海","广州"],"nation":"中国"}
复制代码
从上面的例子,能够看出已经实现了,真正的复制.下面看下图解:
3、深复制【拷贝】方法还有不少种
深复制【拷贝】后,两个对象,包括其内部的元素互不干扰。
一、JSON.parse(JSON.stringify())反序列化
二、JQuery自带的,$.extend(true,{},obj);
三、loadsh.js的实现_.cloneDeep和_.clone(value, true)
复制代码
感兴趣的能够去了解下
鉴于有朋友评论对于JSON.parse(JSON.stringify())反序列化存在局限性,如今作以补充: 照旧,仍是先看下例子: 一、对数组对象进行深层次的拷贝
let obj={
like:'color',
list:{
item:['green','red']
}}
let deepCopy = (JSON.parse(JSON.stringify(obj)));
deepCopy.list.item[0]='yellow';
console.log(deepCopy);//{like:'color',list:{item:['yellow','red']}
console.log(obj);//{like:'color',list:{item:['green','red']}
复制代码
二、针对undefined,function,symbol的拷贝
let obj={x: undefined, y: Object, z: Symbol("")};
console.log('序列化==>'+JSON.stringify(obj)); // 序列化==> '{}'
console.log('反序列化==>'+JSON.parse(JSON.stringify(obj))); // 反序列化==> {}
// 对应一个原型 __proto__
let arr=[undefined, Object, Symbol("")];
console.log('序列化==>'+JSON.stringify(arr));
// 序列化==> '[null,null,null]'
console.log('反序列化 arr==>'+JSON.parse(JSON.stringify(arr)));
// 反序列化 arr==> [null,null,null]
// 反序列化 对应一个原型 __proto__
复制代码
从以上实例得出如下结论:
undefined、任意的函数以及symbol值,在序列化过程当中会被忽略(出如今非数组对象的属性值中时)或者被转换成 null(出如今数组中时)
复制代码
JSON.parse(JSON.stringify())虽不能对undefined,function,symbol进行深拷贝,但使用起来简单,能够知足大部分的场景,具体仍是要根据须要选择使用.
欢迎关注,【前端突击】 猎鹰突击,迎难而上,期待你的加入...