00、深度拷贝
这里有三点需要注意:
1、用new obj.constructor ()
构造函数新建一个空的对象,而不是使用{}
或者[]
,这样可以保持原形链的继承;
2、用obj.hasOwnProperty(key)
来判断属性是否来自原型链上,因为for..in..
也会遍历其原型链上的可枚举属性。
3、上面的函数用到递归算法,在函数有名字,而且名字以后也不会变的情况下,这样定义没有问题。但问题是这个函数的执行与函数名 factorial 紧紧耦合在了一起。为了消除这种紧密耦合的现象,需要使用 arguments.callee
。
function deepClone2(obj) {
if (typeof obj !== 'object') return obj;
if (obj === null) return obj;
if (obj.constructor === Date) return new Date(obj);
if (obj.construcotr === RegExp) return new RegExp(obj);
// let newObj = new obj.constructor();
let newObj = Object.create(Object.getPrototypeOf(obj));保持继承链
let keys = Object.getOwnPropertyNames(obj);//不可枚举属性也可以被复制到
let fun = function(key) {
let val = obj[key];
if (typeof val === 'object') {
newObj[key] = deepClone2(val);
} else {
Object.defineProperty(newObj, key, Object.getOwnPropertyDescriptor(obj, key));
}
};
keys.forEach(fun);
return newObj;
}
var deepClone = 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) {
//如果obj有不可枚举的属性则复制不到,bug
if (obj.hasOwnProperty(key)) { //不遍历其原型链上的属性
var val = obj[key];
//arguments.callee 弃用的话就用函数名
newObj[key] = typeof val === 'object' ? arguments.callee(val) : val; // 使用arguments.callee解除与函数名的耦合
}
}
return newObj;
};
0、对象浅拷贝,for循环
var obj = {a:{b:10}};
function copy(obj){
var newobj = {};
for ( var attr in obj) {
newobj[attr] = obj[attr];
}
return newobj;
}
var obj2 = copy(obj);
obj2.a.b = 20;
alert(obj.a.b); //20
1、拷贝的对象里面如果有引用对象,会受引用对象改变的影响。【浅拷贝】
function copy(obj) {
var copy = Object.create(Object.getPrototypeOf(obj));
var propNames = Object.getOwnPropertyNames(obj);
propNames.forEach(function(name) {
var desc = Object.getOwnPropertyDescriptor(obj, name);
Object.defineProperty(copy, name, desc);
});
return copy;
}
var obj1 = { a: 1, b: 2 };
var obj2 = copy(obj1); // obj2 looks like obj1 now
另一种更简单的写法,是利用 ES2017 才引入标准的Object.getOwnPropertyDescriptors方法。,也是浅拷贝
function copyObject(orig) {
return Object.create(
Object.getPrototypeOf(orig),
Object.getOwnPropertyDescriptors(orig)
);
}
2、对象序列化,这个方法简单得多,但是,就是不能复制函数,【深拷贝】
该方法会忽略值为function以及undefied的字段,而且对date类型的支持也不太友好。
更要紧的是,上述方法只能克隆原始对象自身的值,不能克隆它继承的值,
// Deep Clone
var a = {a:function(){console.log('hello world')},b:{c:1},c:[1,2,3],d:"wanger",e:new Date(),f:null,g:undefined}
obj1 = { a: 0 , b: { c: 0}};
let obj3 = JSON.parse(JSON.stringify(obj1));
obj1.a = 4;
obj1.b.c = 4;
console.log(JSON.stringify(obj3)); // { a: 0, b: { c: 0}}
3、Object.assign 仍然是【浅拷贝】, 针对深拷贝,需要使用其他方法,因为 Object.assign()
拷贝的是属性值。假如源对象的属性值是一个指向对象的引用,它也只拷贝那个引用值。
let obj1 = { a: 0 , b: { c: 0}};
let obj2 = Object.assign({}, obj1);
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}
obj1.a = 1;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}}
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}
obj2.a = 2;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}}
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 0}}
obj2.b.c = 3;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 3}}
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 3}}
4、array 复制 slice(),【浅拷贝】
// 使用slice方法从myCar中创建一个newCar.
var myHonda = { color: 'red', wheels: 4, engine: { cylinders: 4, size: 2.2 } };
var myCar = [myHonda, 2, "cherry condition", "purchased 1997"];
var newCar = myCar.slice(0,2);
//var newCar = myCar.slice();//复制数组
// 输出myCar, newCar,以及各自的myHonda对象引用的color属性.
console.log('myCar = ' + JSON.stringify(myCar));
console.log('newCar = ' + JSON.stringify(newCar));
console.log('myCar[0].color = ' + JSON.stringify(myCar[0].color));
console.log('newCar[0].color = ' + JSON.stringify(newCar[0].color));
// 改变myHonda对象的color属性.
myHonda.color = 'purple';
console.log('The new color of my Honda is ' + myHonda.color);
//输出myCar, newCar中各自的myHonda对象引用的color属性.
console.log('myCar[0].color = ' + myCar[0].color);
console.log('newCar[0].color = ' + newCar[0].color);
/*上述代码输出:
myCar = [{color: 'red', wheels: 4, engine: {cylinders: 4, size: 2.2}}, 2,
'cherry condition', 'purchased 1997']
newCar = [{color: 'red', wheels: 4, engine: {cylinders: 4, size: 2.2}}, 2]
myCar[0].color = red
newCar[0].color = red
The new color of my Honda is purple
myCar[0].color = purple
newCar[0].color = purple
*/
5、array 拷贝 concat() 【浅拷贝】
//浅拷贝,如果a中有引用类型,对a的引用类型值做改变会影响c的值
var a=[1,2,3];
var c=[].concat(a);