深拷贝和浅拷贝
深拷贝和浅拷贝
- 值类型的拷贝的是拷贝值的副本,都互不影响。
- 深拷贝和浅拷贝是针对引用类型(如数组、对象)的拷贝。
一、浅拷贝
- 引用类型拷贝的是“引用“(即指针),之后一方改变都会影响到到另一方。
两种情况
-
情况一:直接赋值,直接拷贝源的是对象(数组)的引用,相互影响。
-
情况二:不是直接赋值(拷贝源对象的实例)
-
属性值是值类型时,直接拷走值的副本,两个都互不影响;
-
属性值的引用类型时,拷贝的是引用(地址),一方改变都会影响到到另一方。
-
实现
对象拷贝:
const obj = {
name:"hjj",
info:{
age:18,
props:["阳光","开朗"]
}
}
//1. ...实现
let copy1={...obj}
console.log(copy1===obj)//false
console.log(copy1.info === obj.info);// true
copy1.info.age=181;
console.log(obj.info.age);//181
copy1.name='HHH1';
console.log(copy1.name,obj.name);//HHH1 hjj
// 2. Object.assign实现
let copy2=Object.assign({},obj)
console.log(copy2===obj)//false
console.log(copy2.info === obj.info);// true
copy2.info.age=182;
console.log(obj.info.age);//182
copy2.name='HHH2';
console.log(copy2.name,obj.name);//HHH2 hjj
// 3. for in实现
let copy3={}
for(let key in obj){
copy3[key]=obj[key]
}
console.log(copy3===obj)//false
console.log(copy3.info === obj.info);// true
copy3.info.age=183;
console.log(obj.info.age);//183
copy3.name='HHH3';
console.log(copy3.name,obj.name);//HHH3 hjj
//4.直接赋值,直接拷贝源对象的引用
let copy4=obj
console.log(copy4===obj)//true
console.log(copy4.info === obj.info);// true
copy4.info.age=184;
console.log(obj.info.age);//184
copy4.name='HHH4';
console.log(copy4.name,obj.name);//HHH4 HHH4
数组拷贝:
const arr=[
{
name:"hjj",
info:{
age:18,
props:["阳光","开朗"]
}
},
0
]
//1. ...实现
let copy1=[...arr]
console.log(copy1===arr);//false
console.log(copy1[0].info === arr[0].info);// true
copy1[0].info.age=181;
console.log(arr[0].info.age);//181
copy1[1]=1
console.log(copy1[1],arr[1]);//1 0
//2.Array.from实现
let copy2=Array.from(arr);
console.log(copy2===arr);//false
console.log(copy2[0].info === arr[0].info);// true
copy2[0].info.age=182;
console.log(arr[0].info.age);//182
copy2[1]=2
console.log(copy2[1],arr[1]);//2 0
// 3、forEach实现
let copy3 = [];
arr.forEach(item=>copy3.push(item));
copy3 = Array.from(arr);
console.log(copy3 === arr);// false
console.log(copy3[0].info === arr[0].info);// true
copy3[0].info.age=183;
console.log(arr[0].info.age);//183
copy3[1]=3
console.log(copy3[1],arr[1]);//3 0
// 4、map实现
let copy4 = arr.map(item=>item);
console.log(copy4 === arr);// false
console.log(copy4[0].info === arr[0].info);// true
copy4[0].info.age=184;
console.log(arr[0].info.age);//184
copy4[1]=4
console.log(copy4[1],arr[1]);//4 0
//5、slice()
let copy5=arr.slice()
console.log(copy5===arr)//true
console.log(copy5[0].info === arr[0].info);// true
copy5[0].info.age=185;
console.log(arr[0].info.age);//185
copy5[1]=5
console.log(copy5[1],arr[1]);//5 0
//6.直接赋值,直接拷贝源数组的引用
let copy6=arr
console.log(copy6===arr)//true
console.log(copy6[0].info === arr[0].info);// true
copy6[0].info.age=186;
console.log(arr[0].info.age);//186
copy6[1]=6
console.log(copy6[1],arr[1]);// 6 6
二、深拷贝
- 创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,拷贝的是“值”而不是“引用”。
- 改变新的数组(对象)的时候,不会改变原数组(对象)。互不影响
实现
方法一:JSON.parse(JSON.stringify(obj))
- 局限:函数不能复制;原型链搞没了...
const obj = {
name:"hjj",
info:{
age:18,
props:["阳光","开朗"]
}
}
let copy1=JSON.parse(JSON.stringify(obj));
console.log(copy1===obj)//false
console.log(copy1.info === obj.info);// false
copy1.info.age=181;
console.log(obj.info.age);//18
方法二:递归拷贝
普通版本
/**
* 深拷贝 普通递归版本
* @param {Object} obj 要拷贝的对象
*/
function deepClone(obj){
// 判断是否数组或对象,确定初始值
let copy = obj instanceof Array ? [] : {}
for (let i in obj) {
if (obj.hasOwnProperty(i)) {
console.log(obj.hasOwnProperty(i),i)
copy[i] = typeof obj[key]==="object"? deepClone(obj[i]) : obj[i]
}
}
return copy
}
function deepClone(obj) {
if (typeof obj !== "object"||obj==null) {
return obj;
}
// 判断是否数组或对象,确定初始值
let result = (obj instanceof Array || Object.prototype.toString.call(obj)=== "[object Array]")?[]:{};
for(let key in obj){
// 保证 key 不是原型属性
if(obj.hasOwnProperty(key)){
result[key]=deepClone(obj[key]);
}
}
return result;
}
//调试1
const obj = {
name:"hjj",
info:{
age:18,
props:["阳光","开朗"]
}
}
deepClone(obj);
//调试2:循环引用会出现死循环问题
let obj={name:'hjj'}
obj.per=obj
deepClone(obj)
解决循环引用问题的版本
/**
* 深拷贝 解决循环引用问题的版本
* @param {Object} obj 要拷贝的对象
* @param {Map} map 用于存储循环引用对象的地址
*/
function deepClone(obj = {}, map = new Map()) {
if (typeof obj !== "object") {
return obj;
}
if (map.get(obj)) {
return map.get(obj);
}
let result = {};
// 初始化返回结果
if (
obj instanceof Array ||
// 加 || 的原因是为了防止 Array 的 prototype 被重写,Array.isArray 也是如此
Object.prototype.toString.call(obj) === "[object Array]"
) {
result = [];
}
// 防止循环引用
map.set(obj, result);
for (const key in obj) {
// 保证 key 不是原型属性
if (obj.hasOwnProperty(key)) {
// 递归调用
result[key] = deepClone(obj[key], map);
}
}
// 返回结果
return result;
}
//调试1
const obj = {
name:"hjj",
info:{
age:18,
props:["阳光","开朗"]
}
}
deepClone(obj);
//调试2 循环引用
let obj={name:'hjj'}
obj.per=obj
deepClone(obj)
**方法:jQuery.extend() **
$.extend( [deep], target, object1 [, objectN ] )
- 用于将一个或多个对象内容合并到目标对象
- deep:默认false-浅拷贝,true-深拷贝
var a = [{m:1}, {n:2},3];
var b =[];
$.extend(true,b,a);
console.log(a === b);// false
a[0].m = 4;
console.log(b[0].m)//1
参考转自:
作者:黄哈哈。
原文链接:https://www.cnblogs.com/jiajia-hjj/p/15271760.html
本博客大多为学习笔记或读书笔记,本文如对您有帮助,还请多推荐下此文,如有错误欢迎指正。