深拷贝 不会影响原始数据
js
let newObj = JSON.parse(JSON.stringify(oldObj))let newObj = JSON.parse(JSON.stringify(oldObj))数组深拷贝
数组实现深拷贝可以使用以下方法
- 使用slice()
- 使用concat()
- ES6扩展运算符
- Array.form()
js
let newArr = oldArr.slice(); // 方案一
let newArr = [].concat(oldArr); // 方案二
let newArr = [...oldArr]; // 方案三
let newArr = Array.from(oldArr); // 方案四let newArr = oldArr.slice(); // 方案一
let newArr = [].concat(oldArr); // 方案二
let newArr = [...oldArr]; // 方案三
let newArr = Array.from(oldArr); // 方案四对象深拷贝
js
let B = JSON.parse(JSON.stringify(A))let B = JSON.parse(JSON.stringify(A))注意
可以转成 JSON 格式的对象才能使用这种方法,如果对象中包含 function 或 RegExp 则不能用这种方法。
- 使用递归
注意
- 用new obj.constructor ()构造函数新建一个空的对象,而不是使用{}或者[],这样可以保持原形链的继承;
- 用obj.hasOwnProperty(key)来判断属性是否来自原型链上,因为for..in..也会遍历其原型链上的可枚举属性。
- 上面的函数用到递归算法,在函数有名字,而且名字以后也不会变的情况下,这样定义没有问题。但问题是这个函数的执行与函数名 factorial 紧紧耦合在了一起。为了消除这种紧密耦合的现象,需要使用 arguments.callee。
js
var clone = function (obj) {
if(obj === null) return null
if(typeof obj !== 'object') return obj;
if(obj.constructor === Date) return new Date(obj);
if(obj.constructor === RegExp) return new RegExp(obj);
var newObj = new obj.constructor (); //保持继承链
for (var key in obj) {
if (obj.hasOwnProperty(key)) { //不遍历其原型链上的属性
var val = obj[key];
newObj[key] = typeof val === 'object' ? arguments.callee(val) : val;
// 使用arguments.callee解除与函数名的耦合
}
}
return newObj;
};var clone = function (obj) {
if(obj === null) return null
if(typeof obj !== 'object') return obj;
if(obj.constructor === Date) return new Date(obj);
if(obj.constructor === RegExp) return new RegExp(obj);
var newObj = new obj.constructor (); //保持继承链
for (var key in obj) {
if (obj.hasOwnProperty(key)) { //不遍历其原型链上的属性
var val = obj[key];
newObj[key] = typeof val === 'object' ? arguments.callee(val) : val;
// 使用arguments.callee解除与函数名的耦合
}
}
return newObj;
};assign
如果对象的属性值为简单类型(如Number,String),通过Object.assign({},Obj)得到的新对象为深拷贝;如果属性值为对象或其它引用类型,那对于这个对象而言其实是浅拷贝的。
使用解构赋值和扩展运算符(...)时,你会发现情况和上面是一样的。
对象数组深拷贝
js
var oldArr = [
{ number: 1 },
{ number: 2 },
{ number: 3 }
];
function objArrDeepCopy (obj) {
var newobj = obj.constructor === Array ? [] : {};
if(typeof obj !== 'object'){
return;
}
for(var i in obj){
newobj[i] = typeof obj[i] === 'object' ? objArrDeepCopy(obj[i]) : obj[i];
}
return newobj
}
var newArr = objArrDeepCopy(oldArr)var oldArr = [
{ number: 1 },
{ number: 2 },
{ number: 3 }
];
function objArrDeepCopy (obj) {
var newobj = obj.constructor === Array ? [] : {};
if(typeof obj !== 'object'){
return;
}
for(var i in obj){
newobj[i] = typeof obj[i] === 'object' ? objArrDeepCopy(obj[i]) : obj[i];
}
return newobj
}
var newArr = objArrDeepCopy(oldArr)多层深拷贝
函数拷贝
浅拷贝 同时改变被原始数据
js
let A = {
name:'1'
}
let B = {}
B = A // Bad 😢
B.name = '???'
console.log(A.name) // ???let A = {
name:'1'
}
let B = {}
B = A // Bad 😢
B.name = '???'
console.log(A.name) // ???js
let array1 = [1,2,3]
let array2 = []
array2 = array1 // Bad 😢
array2[0] = '???'
console.log(array1[0]) // ???let array1 = [1,2,3]
let array2 = []
array2 = array1 // Bad 😢
array2[0] = '???'
console.log(array1[0]) // ???浅拷贝复制的是对象的引用地址,没有开辟新的栈,复制的结果是两个对象指向同一个地址,所以修改其中一个对象的属性,另一个对象的属性也跟着改变了。
liang14658fox