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 相关文章推荐
五个jQuery图片画廊插件 推荐
May 12 Javascript
你需要知道的10个最佳javascript开发实践小结
Apr 15 Javascript
利用JS进行图片的切换即特效展示图片
Dec 03 Javascript
CSS中position属性之fixed实现div居中
Dec 14 Javascript
Vue自定义指令介绍(2)
Dec 08 Javascript
Javascript中将变量转换为字符串的三种方法
Sep 19 Javascript
解决js相同的正则多次调用test()返回的值却不同的问题
Oct 10 Javascript
微信小程序在地图选择地址并返回经纬度简单示例
Dec 03 Javascript
Vue 中使用富文本编译器wangEditor3的方法
Sep 26 Javascript
jquery实现购物车基本功能
Oct 25 jQuery
javascript前端实现多视频上传
Dec 13 Javascript
JavaScript 与 TypeScript之间的联系
Nov 27 Javascript
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
注意:php5.4删除了session_unregister函数
2013/08/05 PHP
Yii2 批量插入、更新数据实例
2017/03/15 PHP
深入理解PHP的远程多会话调试
2017/09/21 PHP
PHP设计模式之单例模式定义与用法分析
2019/03/26 PHP
详解如何实现Laravel的服务容器的方法示例
2019/04/15 PHP
PHP程序员简单的开展服务治理架构操作详解(一)
2020/05/14 PHP
jQuery EasyUI API 中文文档 搜索框
2011/09/29 Javascript
jquery高效反选具体实现
2013/05/05 Javascript
js鼠标滑轮滚动事件绑定的简单实例(兼容主流浏览器)
2014/01/14 Javascript
IE中getElementsByName()对有些元素无效的解决方案
2014/09/28 Javascript
jquery引用方法时传递参数原理分析
2014/10/13 Javascript
谈谈JavaScript类型系统之Math
2016/01/06 Javascript
jQuery web 组件 后台日历价格、库存设置的代码
2016/10/14 Javascript
微信小程序(三):网络请求
2017/01/13 Javascript
让div运动起来 js实现缓动效果
2017/07/06 Javascript
NodeJS实现自定义流的方法
2018/08/01 NodeJs
Vue+Typescript中在Vue上挂载axios使用时报错问题
2019/08/07 Javascript
vue中使用百度脑图kityminder-core二次开发的实现
2019/09/26 Javascript
微信小程序在text文本实现多种字体样式
2019/11/08 Javascript
js键盘事件实现人物的行走
2020/01/17 Javascript
[49:59]KG vs Mineski 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/16 DOTA
python 根据正则表达式提取指定的内容实例详解
2016/12/04 Python
Python语言实现百度语音识别API的使用实例
2017/12/13 Python
python版学生管理系统
2018/01/10 Python
通过python实现弹窗广告拦截过程详解
2019/07/10 Python
python 叠加等边三角形的绘制的实现
2019/08/14 Python
python模拟点击玩游戏的实例讲解
2020/11/26 Python
英国领先的男装设计师服装购物网站:Mainline Menswear
2018/02/04 全球购物
美国婴儿和儿童服装购物网站:PatPat
2020/10/01 全球购物
C语言50道问题
2014/10/23 面试题
2014财务人员自我评价范文
2014/09/21 职场文书
诚实守信主题班会
2015/08/13 职场文书
初二数学教学反思
2016/02/17 职场文书
不会写演讲稿,快来看看这篇文章!
2019/08/06 职场文书
如何使用PostgreSQL进行中文全文检索
2021/05/27 PostgreSQL
Django实现聊天机器人
2021/05/31 Python