JavaScript最完整的深浅拷贝实现方式详解


Posted in Javascript onFebruary 28, 2022

深浅拷贝:

内存中一共分为栈内存和堆内存两大区域,所谓深浅拷贝主要是对js引用类型数据进行拷贝一份,浅拷贝就是引用类型数据相互赋值之后,例obj1=obj2;如果后面的操作中修改obj1或者obj2,这个时候数据是会进行相应的变化的,因为在内存中引用类型数据是存储在堆内存中,堆内存中存放的是引用类型的值,同时会有一个指针地址指向栈内存,两个引用类型数据地址一样,如果其中一个发生变化另外一个都会有影响;而深拷贝则不会,深拷贝是会在堆内存中重新开辟一块空间进行存放;

简单来说就是B复制了A,如果A发生了改变,如果B随之变化,那么是浅拷贝,如果B并没有发生变化,则是深拷贝。

基本类型拷贝

let a = 1;
let b = a;
b = 2;
console.log(a);//1
console.log(b);//2

a,b都是属于基本类型,基本类型的复制是不会影响对方的,因为基本类型是每一次创建变量都会在栈内存中开辟一块内存,用来存放值,所以对基本类型进行拷贝是不会对另外一个变量有影响的,属于深拷贝。

数组拷贝 

concat() slice()

//  concat()
let list = ['a','b','c'];
let list2 = list.concat();
list2.push('d')
console.log(list);//['a','b','c']
console.log(list2);//['a','b','c','d']
//  slice()
let list = ['a','b','c'];
let list2 = list.slice();
list2.push('d')
console.log(list);//['a','b','c']
console.log(list2);//['a','b','c','d']

上面两种方法只能实现数组类型里面的单层深拷贝,如果是多层无法实现深拷贝。

//二维数组
let list = ['a','b','c',['d','e','f']];
let list2 = list.concat();
list2[3][0] = 'a';
console.log(list);
console.log(list2);

JavaScript最完整的深浅拷贝实现方式详解

可以看到原二维数组的值也发生了变化,说明没有实现深拷贝。

由此总结,concat和slice只能实现一维数组的深拷贝,不能对多维数组进行深拷贝,所以并不是一个完美的深拷贝方式。

对象拷贝

new Object()

let a = {id:1,name:'a',obj:{id:999}};
let b = new Object();
b.id = a.id;
b.name = a.name;
b.obj = a.obj;
a.name = 'b';
a.obj.id = 888;
console.log(a);
console.log(b);

 

JavaScript最完整的深浅拷贝实现方式详解

a.name更改并没有影响到b.name,好像可以看作深拷贝,但第二层obj里面里面的id随之更改了,因此其实并不是深拷贝。

Object.assign

let a = {id:1,name:'a',obj:{id:999}};
function fun(obj){
    let o = {};
    Object.assign(o,obj);
    return o;
}
let a2 = fun(a);
a2.name ='a2';
a2.obj.id = 888;
console.log(a);
console.log(a2);

JavaScript最完整的深浅拷贝实现方式详解

以上两种方法,对于一层对象都能实现深拷贝,但对于多层对象则无法实现,因此也不是一种完美的深拷贝方式。

JSON.parse(JSON.stringify( ))

let a = {
    name : 'a',
    age : 20,
    obj : {id:999},
    action : function(){
        console.log(this.name);
    }
}
let b = JSON.parse(JSON.stringify(a));
a.name = 'b';
a.obj.id = 888;
console.log(a);
console.log(b);

JavaScript最完整的深浅拷贝实现方式详解

单层对象name和多层对象obj.id的改变都没影响到原对象,因此是一个比较完美的深拷贝,但是能看到function好像并没有被拷贝。

可以看出这个方法对于一层和多层都能实现深拷贝,但是这个方法的缺陷是不能拷贝Function,所以在使用时,一定要注意数据类型。

递归

let a = {
    name:'a',
    skin:["red","blue","yellow",["123","456"]],
    child:{
        work:'none',
        obj:{
            id:999
        }
    },
    action:function(){
        console.log(this.name);
    }
}
//封装的递归方法
    function copyWid(obj){
        let newObj = Array.isArray(obj)?[]:{};
        for (var i in obj){
            if(typeof obj[i] === 'object'){  //判断是不是对象(数组或对象)
               newObj[i] = copyWid(obj[i])  //递归解决多层拷贝
            }else{
                newObj[i] = obj[i]   
            }
        }
        return newObj;
    };
    let b = copyWid(a);
    b.child.obj.id =888;
    b.skin[3][0] = "pink";
    console.log(a);
    console.log(b);

JavaScript最完整的深浅拷贝实现方式详解

可以看到,无论是多层的对象还是多层的数组,都能实现深拷贝,而且能拷贝函数,这个是目前来说最完美的深拷贝方法。

通过这个递归能实现一个比较完美的深拷贝,能弥补上述提到的所有方法中的缺点。

展开运算符

let a = {name:'a',id:99};//如果是数组[xx,xx,xx],{...a}需要改成[...a]
let b ={...a};  //[...a]
a.id =88;
console.log(a);
console.log(b);

JavaScript最完整的深浅拷贝实现方式详解

这个方法能实现对象数组单层时的深拷贝,但是多层无法实现深拷贝。

以上这么多方法,最优解应该属于JSON和递归的方法(递归解决了JSON无法拷贝函数方法的问题),但是根据需求数据类型的不同,可以选择更简单的方式。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注三水点靠木的更多内容! 

Javascript 相关文章推荐
filemanage功能中用到的common.js
Apr 08 Javascript
JavaScript 实现模态对话框 源代码大全
May 02 Javascript
JS中操作JSON总结
Dec 06 Javascript
js 判断图片是否加载完以及实现图片的预下载
Aug 14 Javascript
使用Jquery实现每日签到功能
Apr 03 Javascript
浅析创建javascript对象的方法
May 13 Javascript
实例详解jQuery的无new构建
Aug 02 Javascript
设置jquery UI 控件的大小方法
Dec 12 Javascript
js图片放大镜实例讲解(必看篇)
Jul 17 Javascript
ES6小技巧之代替lodash
Jun 07 Javascript
Vue ​v-model相关知识总结
Jan 28 Vue.js
Vue+TypeScript中处理computed方式
Apr 02 Vue.js
Vue全局事件总线你了解吗
Feb 24 #Vue.js
Vue的生命周期一起来看看
Vue的过滤器你真了解吗
Feb 24 #Vue.js
Vue监视数据的原理详解
Feb 24 #Vue.js
Vue的列表之渲染,排序,过滤详解
一篇文章了解正则表达式的替换技巧
Feb 24 #Javascript
最新最全的手机号验证正则表达式
Feb 24 #Javascript
You might like
THINKPHP+JS实现缩放图片式截图的实现
2010/03/07 PHP
php中判断文件存在是用file_exists还是is_file的整理
2012/09/12 PHP
table标签的结构与合并单元格的实现方法
2013/07/24 PHP
PHP关于IE下的iframe跨域导致session丢失问题解决方法
2013/10/10 PHP
php使用Session和文件统计在线人数
2015/07/04 PHP
PHP使用finfo_file()函数检测上传图片类型的实现方法
2017/04/18 PHP
laravel框架中视图的基本使用方法分析
2019/11/23 PHP
javascript 避免闭包引发的问题
2009/03/17 Javascript
Extjs4 消息框去掉关闭按钮(类似Ext.Msg.alert)
2013/04/02 Javascript
Jquery原生态实现表格header头随滚动条滚动而滚动
2014/03/18 Javascript
js图片滚动效果时间可随意设定当鼠标移上去时停止
2014/06/26 Javascript
在JavaScript的正则表达式中使用exec()方法
2015/06/16 Javascript
js拖拽的原型声明和用法总结
2016/04/04 Javascript
js 实现获取name 相同的页面元素并循环遍历的方法
2017/02/14 Javascript
关于vue-router路径计算问题
2017/05/10 Javascript
angular directive的简单使用总结
2017/05/24 Javascript
jQuery实现腾讯信用界面(自制刻度尺)样式
2017/08/15 jQuery
javascript中floor使用方法总结
2019/02/02 Javascript
vue实现图片上传预览功能
2019/12/23 Javascript
解决vue.js中settimeout遇到的问题(时间参数短效果不稳定)
2020/07/21 Javascript
原生js实现弹窗消息动画
2020/11/20 Javascript
新建文件时Pycharm中自动设置头部模板信息的方法
2020/04/17 Python
python写文件时覆盖原来的实例方法
2020/07/22 Python
实例讲解CSS3中的box-flex弹性盒属性布局
2016/06/09 HTML / CSS
施华洛世奇天猫官方旗舰店:SWAROVSKI
2017/04/17 全球购物
德国古洛迷亚百货官网:GALERIA Kaufhof
2017/06/20 全球购物
Gtech官方网站:地毯清洁器、吸尘器及园艺设备
2018/05/23 全球购物
英国网上自行车商店:Tredz Bikes
2019/10/29 全球购物
介绍一下write命令
2014/08/10 面试题
活动总结格式范文
2014/04/26 职场文书
基层党员公开承诺书
2014/05/29 职场文书
详细的本科生职业生涯规划范文
2014/09/16 职场文书
2015个人简历自我评价语
2015/03/11 职场文书
2019通用版新员工入职培训方案!
2019/07/11 职场文书
教师学期述职自我鉴定
2019/08/16 职场文书
Pytorch GPU内存占用很高,但是利用率很低如何解决
2021/06/01 Python