目录
扫描二维码关注公众号,回复:
14259774 查看本文章
![](/qrcode.jpg)
一、区别
浅拷贝(shallow copy):
复制指向某个对象的指针,而不复制对象本身,新旧对象共享一块内存;浅拷贝就是只拷贝一层,更深层次对象级别只拷贝引用(地址)当拷贝的新对象发生改变时,原对象也会发生相同的改变,也就是说,浅拷贝会影响原来的元素
深拷贝(deep copy):
每一级的数据都会拷贝 深拷贝只拷贝内容,两个对象拥有不同的地址,当拷贝出来的对象发生改变时,原对象内容不会改变,两者互不影响
二、实现方法:
浅拷贝
1、直接赋值法:
var arr = [1,2,3]
var newarr = arr;
newarr[1] = 5;
console.log(arr,newarr);//[1, 5, 3],[1, 5, 3]
深拷贝
1、Object.assign()
当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。
let foo = {
a: 1,
b: 2,
c: {
d: 1,
}
}
let bar = {};
Object.assign(bar, foo);
foo.a++;
foo.a === 2 //true
bar.a === 1 //true
foo.c.d++;
foo.c.d === 2 //true
bar.c.d === 1 //false
bar.c.d === 2 //true
2、转成JSON
用JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象。
但这种方法的缺陷是会破坏原型链,并且无法拷贝属性值为function的属性
var obj1 = { body: { a: 10 } };
var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.body.a = 20;
console.log(obj1); // { body: { a: 10 } }
console.log(obj2); // { body: { a: 20 } }
console.log(obj1 === obj2); // false
console.log(obj1.body === obj2.body); // false
3、递归
采用递归的方法去复制拷贝对象
//使用递归的方式实现数组、对象的深拷贝
function deepClone1(obj) {
//判断拷贝的要进行深拷贝的是数组还是对象,是数组的话进行数组拷贝,对象的话进行对象拷贝
var objClone = Array.isArray(obj) ? [] : {};
//进行深拷贝的不能为空,并且是对象或者是
if (obj && typeof obj === "object") {
for (key in obj) {
if (obj.hasOwnProperty(key)) {
if (obj[key] && typeof obj[key] === "object") {
objClone[key] = deepClone1(obj[key]);
} else {
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
4. 通过jQuery的extend方法实现深拷贝
var array = [1,2,3,4];
var newArray = $.extend(true,[],array);
jQuery.extend源码
// extend方法为jQuery对象和init对象的prototype扩展方法
// 同时具有独立的扩展普通对象的功能
jQuery.extend = jQuery.fn.extend = function() {
/*
*target被扩展的对象
*length参数的数量
*deep是否深度操作
*/
var options, name, src, copy, copyIsArray, clone,
target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false;
// target为第一个参数,如果第一个参数是Boolean类型的值,则把target赋值给deep
// deep表示是否进行深层面的复制,当为true时,进行深度复制,否则只进行第一层扩展
// 然后把第二个参数赋值给target
if ( typeof target === "boolean" ) {
deep = target;
target = arguments[1] || {};
// 将i赋值为2,跳过前两个参数
i = 2;
}
// target既不是对象也不是函数则把target设置为空对象。
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
target = {};
}
// 如果只有一个参数,则把jQuery对象赋值给target,即扩展到jQuery对象上
if ( length === i ) {
target = this;
// i减1,指向被扩展对象
--i;
}
// 开始遍历需要被扩展到target上的参数
for ( ; i < length; i++ ) {
// 处理第i个被扩展的对象,即除去deep和target之外的对象
//options 是来接收除了第一个参数外的所有参数。中间桥梁的作用吧
if ( (options = arguments[ i ]) != null ) {
// 遍历第i个对象的所有可遍历的属性
for ( name in options ) {
// 根据被扩展对象的键获得目标对象相应值,并赋值给src
src = target[ name ];
// 得到被扩展对象的值
copy = options[ name ];
// Prevent never-ending loop
// 若参数中字段的值就是目标参数,停止赋值,进行下一个字段的赋值
// 这是为了防止无限的循环嵌套
//var _default = {name : 'wenzi'};
//var obj = {name : _default}
//$.extend(_default, obj);
//如果没有这个判断,则结果是:_default = {name : _default};
//如果有这个判断,则结果是:_default = {name : wenzi};
// _default是object类型,里面有个字段name,值是_default,而_default是object类型,里面有个字段name,值是_default......,无限的循环下去。于是jQuery中直接不进行操作,跳过这个字段,进行下一个字段的操作。
if ( target === copy ) {
continue;
}
// 当用户想要深度操作时,递归合并
// copy是纯对象或者是数组
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
// 如果是数组
if ( copyIsArray ) {
// 将copyIsArray重新设置为false,为下次遍历做准备。
copyIsArray = false;
// 判断被扩展的对象中src是不是数组
clone = src && jQuery.isArray(src) ? src : [];
} else {
// 判断被扩展的对象中src是不是纯对象
clone = src && jQuery.isPlainObject(src) ? src : {};
}
// 递归调用extend方法,继续进行深度遍历
target[ name ] = jQuery.extend( deep, clone, copy );
// 如果不需要深度复制,则直接把copy(第i个被扩展对象中被遍历的那个键的值)
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
// 原对象被改变,因此如果不想改变原对象,target可传入{}
return target;
};
5. lodash函数库实现深拷贝
lodash很热门的函数库,提供了 lodash.cloneDeep()实现深拷贝