浅拷贝:只是拷贝了基本类型的数据,而引用类型数据,复制后也是会发生引用,我们把这种拷贝叫做浅拷贝(浅复制)
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。
深拷贝:在堆中重新分配内存,并且把源对象所有属性都进行新建拷贝,以保证深拷贝的对象的引用图不包含任何原有对象或对象图上的任何对象,拷贝后的对象与原来的对象是完全隔离,互不影响;
浅拷贝:
1.直接赋值
<script>
var obj = {
name:'wade',
age:37
}
// 直接赋值
var cloneObj = obj;
cloneObj.name = 'james';
console.log(obj);
console.log(cloneObj);
</script>
修改新对象的属性,原对象也会发生改变
2.Object.assign()
可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign()
进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。
<script>
var obj = {
name:'wade',
age:37,
friend:{
name:'james',
age:34
}
}
var cloneObj = Object.assign({},obj)
obj.friend.name = 'rose';
console.log(obj);
console.log(cloneObj);
</script>
注意:当object只有一层的时候,是深拷贝
<script>
var obj = {
name:'wade',
age:37
}
var cloneObj = Object.assign({},obj)
obj.name = 'rose';
console.log(obj);
console.log(cloneObj);
</script>
3.ES6 扩展运算符 (...)
<script>
var obj = {
name:'wade',
age:37,
friend:{
name:'james',
age:34
}
}
var cloneObj = {...obj};
obj.friend.name = 'curry'
console.log(obj);
console.log(cloneObj);
</script>
注意:当object只有一层的时候,也是深拷贝
<script>
var obj = {
name:'wade',
age:37
}
var cloneObj = {...obj};
obj.name = 'curry'
console.log(obj);
console.log(cloneObj);
</script>
Array的slice和concat方法
不修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。
原数组的元素会按照下述规则拷贝:
- 如果该元素是个对象引用(不是实际的对象),slice 会拷贝这个对象引用到新的数组里。两个对象引用都引用了同一个对象。如果被引用的对象发生改变,则新的和原来的数组中的这个元素也会发生改变。
- 对于字符串、数字及布尔值来说(不是 String、Number 或者 Boolean 对象),slice 会拷贝这些值到新的数组里。在别的数组里修改这些字符串或数字或是布尔值,将不会影响另一个数组。
4.Array.prototype.concat()
<script>
var arr = ['wade',37,{
name:'james',
age:34
}]
var cloneArr = arr.concat();
arr[2].name = 'curry';
console.log(arr);
console.log(cloneArr);
</script>
修改原对象会修改到新对象:
5.Array.prototype.slice()
<script>
var arr = ['wade',37,{
name:'james',
age:34
}]
var cloneArr = arr.slice();
arr[2].name = 'curry';
console.log(arr);
console.log(cloneArr);
</script>
同样修改原对象会修改到新对象:
jQuery中的 $.extend
6.$.extend(deep,target,object1,objectN)
deep: 如过设为true为深拷贝,默认是false浅拷贝
target:要拷贝的目标对象
object1:待拷贝到第一个对象的对象
objectN:待拷贝到第N个对象的对象
<script>
var obj = {
name:'wade',
age:37,
friend:{
name:'james',
age:34
}
}
var cloneObj = {};
// deep 默认为 false 为浅拷贝
$.extend(cloneObj,obj);
obj.friend.name = 'rose';
console.log(obj);
console.log(cloneObj);
</script>
修改原对象会修改到新对象:
深拷贝:
1.$.extend(deep,target,object1,objectN)
<script>
var obj = {
name:'wade',
age:37,
friend:{
name:'james',
age:34
}
}
var cloneObj = {};
// deep 设为 true 为深拷贝
$.extend(true,cloneObj,obj);
obj.friend.name = 'rose';
console.log(obj);
console.log(cloneObj);
</script>
修改原对象不会修改到新对象:
2.JSON.parse(JSON.stringify())
用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。
<script>
var obj = {
name:'wade',
age:37,
friend:{
name:'james',
age:34
}
}
var cloneObj = JSON.parse(JSON.stringify(obj))
obj.name = 'rose';
obj.friend.name = 'curry';
console.log(obj);
console.log(cloneObj);
</script>
注意:这种方法虽然可以实现数组或对象深拷贝,但不能处理函数。
这是因为 JSON.stringify()
方法是将一个JavaScript值(对象或者数组)转换为一个 JSON字符串,不能接受函数。(同样,正则对象也一样,在JSON.parse解析时会发生错误)。
<script>
var obj = {
name:'wade',
age:37,
friend:{
name:'james',
age:34
},
sing:function(){}
}
var cloneObj = JSON.parse(JSON.stringify(obj))
console.log(obj);
console.log(cloneObj);
</script>
在原对象中有函数,拷贝之后,新对象中没有
3.手写递归方法(1)
<script>
function deepCopy(oldObj, newobj) {
for (var key in oldObj) {
var item = oldObj[key];
// 判断是否是对象
if (item instanceof Object) {
newobj[key] = {}; //定义一个空的对象来接收拷贝的内容
deepCopy(item, newobj[key]); //递归调用
// 判断是否是数组
} else if (item instanceof Array) {
newobj[key] = []; //定义一个空的数组来接收拷贝的内容
deepCopy(item, newobj[key]); //递归调用
} else {
newobj[key] = oldObj[key];
}
}
}
var obj = {
name:'wade',
age:37,
friend:{
name:'james',
age:34
}
}
var cloneObj = {};
deepCopy(obj,cloneObj);
obj.name = 'rose';
obj.friend.name = 'curry';
console.log(obj);
console.log(cloneObj);
</script>
改变原对象不会修改新对象
4.手写递归方法(2)
<script>
function deepClone(target) {
let result;
// 判断是否是对象类型
if (typeof target === 'object') {
// 判断是否是数组类型
if (Array.isArray(target)) {
result = []; // 如果是数组,创建一个空数组
for (let i in target) { // 遍历 递归调用
result.push(deepClone(target[i]))
}
// 再判断是否是 null
} else if (target === null) {
result = null; // 如果是,直接等于 null
// 判断是否是正则对象
} else if (target.constructor === RegExp) {
result = target; // 如果是,直接赋值拷贝
} else { // 则是对象
result = {}; // 创建一个空对象
for (let i in target) { // 遍历 递归调用
result[i] = deepClone(target[i]);
}
}
} else {
// 表示不是对象类型,则是简单数据类型 直接赋值
result = target;
}
// 返回结果
return result;
}
var obj = {
name:'wade',
age:37,
friend:{
name:'james',
age:34
}
}
var cloneObj = {};
deepCopy(obj,cloneObj);
obj.name = 'rose';
obj.friend.name = 'curry';
console.log(obj);
console.log(cloneObj);
</script>
改变原对象不会修改新对象