深拷贝和浅拷贝
浅拷贝
只复制最外一层,里面的都还是相同引用
如果拷贝的是基本数据类型,拷贝的就是基本数据类型的值
如果拷贝的是引用数据类型,拷贝的仅仅只是内存地址(引用)
Object.assign
Object.assign,将所有可枚举(Object.propertyIsEnumerable() 返回 true)的自有属性从一个或多个源对象复制到目标对象,返回修改后的对象
js
Object.assign(target, ...sources)
扩展运算符
使用扩展运算符可以在构造字面量对象的时候,进行属性的拷贝
js
let cloneObj = { ...obj };
数组浅拷贝
Array.prototype.slice
slice()方法是JavaScript的数组方法,该方法可以从已有数组中返回选定的元素,不会改变原始数组
js
array.slice(start, end)
slice方法不会修改原数组,只会返回一个浅拷贝了原数组中的元素的一个新数组。
如果向两个数组任一中添加了新元素,则另一个不会受到影响
Array.prototype.concat
concat()方法用于合并两个或多个数组,此方法不会更改原始数组,而是返回一个新数组
js
arrayObject.concat(arrayA,arrayB,...,arrayZ)
如果省略了所有参数,会返回调用此方法的现存数组的一个浅拷贝(新数组)
手写实现
js
function shallowCopy(params){
if(!params || typeof params!=="object")return params;
let newObject = Array.isArray(params) ? [] : {};
for(let key in params){
if(params.hasOwnProperty(key)){
newObject[key]=params[key];
}
}
return newObject;
}
深拷贝
JSON.stringify
原理是利用JSON.stringify将JavaScript对象序列化成为JSON字符串,并将对象里面的内容转换为字符串,再使用JSON.parse来反序列化,将字符串生成一个新的JavaScript对象
js
let obj1={
a:0,
b:{
c:0
}
};
let obj2=JSON.parse(JSON.stringigy(obj1))l
obj1.a=1;
obj2.b.c=1;
console.log(obj1);
console.log(obj2);
问题:
拷贝的对象中如果有function、undefined、symbol,当使用JSON.stringigy()进行处理之后,都会消失
无法拷贝不可枚举的属性
无法拷贝对象的原型链
拷贝Date引用类型会变成字符串
拷贝RegExp引用类型会变成空对象
对象中含有NaN,Infinity以及-Infinity,JSON序列化的结果会变成null
无法拷贝对象的循环应用,即对象成环(obj[key]=obj)
函数库loadsh
提供_.cloneDeep()来做深拷贝
js
var _=require('lodash');
var obj1={
a:1,
b:{f:{g:1}},
c:[1,2,3]
};
var obj2=_.cloneDeep(obj1);
console.log(obj1.b.f===obj2.b.f);//false
手写深拷贝
js
function deepClone(source,map=new Map()){
if(source instanceof Object === false)return source;
let target=Array.isArray(source) ? [] : {};
/* -----------解决环引用爆栈问题-------------- */
if(map.get(source)){
// 已存在则直接返回
return map.get(source);
}
// 不存在则第一次设置
map.set(source,target);
for(let i in source){
if(source.hasOwnProperty(i)){
if(typeof source[i]==='object'){
// 传递map
target[i]=deepClone(source[i],map);
}else{
target[i]=source[i];
}
}
}
}