摘要:总结综上所述,数组的深拷贝比较简单,方法没有什么争议,对象的深拷贝,比较好的方法是用的方法实现,或者递归实现,比较简单的深复制可以使用实现参考资料知乎中的深拷贝和浅拷贝深入剖析的深复制
深浅复制对比
因为JavaScript存储对象都是存地址的,所以浅复制会导致 obj 和obj1 指向同一块内存地址。我的理解是,这有点类似数据双向绑定,改变了其中一方的内容,都是在原来的内存基础上做修改会导致拷贝对象和源对象都发生改变,而深复制一般都是开辟一块新的内存地址,将原对象的各个属性逐个复制出去。对拷贝对象和源对象各自的操作不影响另一方
代码层面实现深浅复制//数组拷贝
//浅复制,双向改变,指向同一片内存空间
let arr = [1, 2, 3];
let arr1 = arr;
arr1[1] = "test";
console.log("shallow copy: " + arr + " " + arr1); //shallow copy: 1,test,3 1,test,3
//深复制,开辟新的内存区
//方法一:slice,原理:slice返回一个新数组
let deepArr = [1, 2, 3];
let deepArr1 = deepArr.slice(0);
deepArr1[1] = "test";
console.log("deep copy: " + deepArr + " " + deepArr1); //deep copy: 1,2,3 1,test,3
//方法二:concat,原理:concat返回一个新数组
let deepArr2 = [1, 2, 3];
let deepArr3 = deepArr2.concat();
deepArr3[1] = "test";
console.log("deep copy: " + deepArr2 + " " + deepArr3); //deep copy: 1,2,3 1,test,3
//知乎看到的深复制方法,这个函数可以深拷贝 对象和数组,很遗憾,对象里的函数会丢失
deepCloneObj = obj => {
let str, newobj = obj.constructor === Array ? [] : {};
if(typeof obj !== "object") {
return;
}else if(window.JSON) {
/*好处是非常简单易用,但是坏处也显而易见,会丢失很多东西,这会抛弃对象的constructor,
也就是深复制之后,无论这个对象原本的构造函数是什么,在深复制之后都会变成Object。
另外诸如RegExp对象是无法通过这种方式深复制的。
*/
str = JSON.stringify(obj);
newobj = JSON.parse(str);
//console.log(JSON.parse(JSON.stringify(/[0-9]/)));
}else {
for(let i in obj) {
newobj[i] = typeof obj[i] === "object" ? deepCloneObj(obj[i]) : obj[i];
}
}
return newobj;
}
let deepArr4 = {
a: 1,
b: "test",
c: [1, 2, 3],
d: {
"a": "d:a",
"b": "d:b"
}
}
deepArr5 = deepCloneObj(deepArr4);
deepArr5["a"] = "testa";
console.log("deep copy: " + JSON.stringify(deepArr4) + " " + JSON.stringify(deepArr5));
/*deep copy: {"a":1,"b":"test","c":[1,2,3],"d":{"a":"d:a","b":"d:b"}}
{"a":"testa","b":"test","c":[1,2,3],"d":{"a":"d:a","b":"d:b"}}
*/
第三方库实现深浅复制
1.jQuery.extend
第一个参数可以是布尔值,用来设置是否深度拷贝的:
jQuery.extend(true, { a : { a : "a" } }, { a : { b : "b" } } );
jQuery.extend( { a : { a : "a" } }, { a : { b : "b" } } );
下面是源码,可以看看
jQuery.extend = jQuery.fn.extend = function() {
var src, copyIsArray, copy, name, options, clone,
target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false;
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
// skip the boolean and the target
target = arguments[ i ] || {};
i++;
}
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
target = {};
}
// extend jQuery itself if only one argument is passed
if ( i === length ) {
target = this;
i--;
}
for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
if ( (options = arguments[ i ]) != null ) {
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
// Prevent never-ending loop
if ( target === copy ) {
continue;
}
// Recurse if we"re merging plain objects or arrays
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
if ( copyIsArray ) {
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : [];
} else {
clone = src && jQuery.isPlainObject(src) ? src : {};
}
// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );
// Don"t bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
// Return the modified object
return target;
};
2.lodash —— _.clone() / _.cloneDeep()
在lodash中关于复制的方法有两个,分别是_.clone()和_.cloneDeep()。其中_.clone(obj, true)等价于_.cloneDeep(obj)。使用上,lodash和jquery并没有太大的区别,但看了源码会发现, jQuery 不过60多行。可 lodash 中与深复制相关的代码却有上百行.jQuery 无法正确深复制 JSON 对象以外的对象,lodash 花了大量的代码来实现 ES6 引入的大量新的标准对象。更厉害的是,lodash 针对存在环的对象的处理也是非常出色的。因此相较而言,lodash 在深复制上的行为反馈比jquery好很多,是更拥抱未来的一个第三方库。
综上所述,数组的深拷贝比较简单,方法没有什么争议,对象的深拷贝,比较好的方法是用lodash的方法实现,或者递归实现,比较简单的深复制可以使用JSON.parse(JSON.stringify(obj))实现
参考资料知乎:javascript中的深拷贝和浅拷贝
深入剖析 JavaScript 的深复制
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/79930.html
摘要:二这么分的好处就是在于节省内存资源,便于合理回收内存详解中的深浅复制有了上面的铺垫,那么我们理解起深浅复制就变得容易的许多。 前言 对于前端开发来说,我们经常能够遇到的问题就是js的深浅复制问题,通常情况下我们解决这个问题的方法就是用JSON.parse(JSON.Stringify(xx))转换或者用类似于Inmmutable这种第三方库来进行深复制,但是我们还是要弄懂其中原理,这样...
摘要:深拷贝相比于浅拷贝速度较慢并且花销较大。所以在赋值完成后,在栈内存就有两个指针指向堆内存同一个数据。结果如下扩展运算符只能对一层进行深拷贝如果拷贝的层数超过了一层的话,那么就会进行浅拷贝那么我们可以看到和展开原算符对于深浅拷贝的结果是一样。 JS中数据类型 基本数据类型: undefined、null、Boolean、Number、String和Symbol(ES6) 引用数据类型:...
摘要:基本数据类型的复制很简单,就是赋值操作,所以深浅拷贝也是针对,这类引用类型数据。它会抛弃对象的。另外,查资料过程中还看到这么一个词结构化克隆算法还有这一篇资料也有参考,也写得比较详细了的深浅拷贝 基本数据类型的复制很简单,就是赋值操作,所以深浅拷贝也是针对Object,Array这类引用类型数据。 浅拷贝对于字符串来说,是值的复制,而对于对象来说则是对对象地址的复制;而深拷贝的话,它不...
阅读 1174·2021-10-09 09:58
阅读 910·2021-08-27 16:24
阅读 2000·2019-08-30 14:15
阅读 2670·2019-08-30 11:04
阅读 2357·2019-08-29 18:43
阅读 2407·2019-08-29 15:20
阅读 3033·2019-08-26 12:20
阅读 1975·2019-08-26 11:44