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 相关文章推荐
JS动态创建Table,Tr,Td并赋值的具体实现
Jul 05 Javascript
Javascript this 关键字 详解
Oct 22 Javascript
jQuery找出网页上最高元素的方法
Mar 20 Javascript
jQuery子元素过滤选择器用法示例
Sep 09 Javascript
js前端实现多图图片上传预览的两个方法(推荐)
Nov 18 Javascript
vue.js学习之递归组件
Dec 13 Javascript
详解react-webpack2-热模块替换[HMR]
Aug 03 Javascript
javascript 日期相减-在线教程(附代码)
Aug 17 Javascript
微信小程序自定义头部导航栏(组件化)
Nov 15 Javascript
Vue.js 实现地址管理页面思路详解(地址添加、编辑、删除和设置默认地址)
Dec 11 Javascript
javascript实现页面的实时时钟显示示例
Aug 06 Javascript
js仿京东放大镜效果
Aug 09 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
php 判断是否是中文/英文/数字示例代码
2013/09/30 PHP
Zend Framework教程之前端控制器Zend_Controller_Front用法详解
2016/03/07 PHP
PHP简单实现防止SQL注入的方法
2018/03/13 PHP
Javascript模板技术
2007/04/27 Javascript
jquery得到iframe src属性值的方法
2014/09/25 Javascript
基于JavaScript怎么实现让歌词滚动播放
2015/11/03 Javascript
简介EasyUI datagrid editor combogrid搜索框的实现
2016/04/01 Javascript
JavaScript+Html5实现按钮复制文字到剪切板功能(手机网页兼容)
2017/03/30 Javascript
vue2.0实现导航菜单切换效果
2017/05/08 Javascript
Three.js利用性能插件stats实现性能监听的方法
2017/09/25 Javascript
让bootstrap的carousel支持滑动滚屏的实现代码
2017/11/27 Javascript
JS中使用new Option()实现时间联动效果
2018/12/10 Javascript
vue中子组件传递数据给父组件的讲解
2019/01/27 Javascript
详解小程序毫秒级倒计时(适用于拼团秒杀功能)
2019/05/05 Javascript
策略模式实现 Vue 动态表单验证的方法
2019/09/16 Javascript
微信小程序实现组件顶端固定或底端固定效果(不随滚动而滚动)
2020/04/09 Javascript
JS如何实现封装列表右滑动删除收藏按钮
2020/07/23 Javascript
解决nuxt 自定义全局方法,全局属性,全局变量的问题
2020/11/05 Javascript
web.py在模板中输出美元符号的方法
2014/08/26 Python
Python实现批量将word转html并将html内容发布至网站的方法
2015/07/14 Python
tensorflow实现简单的卷积神经网络
2018/05/24 Python
Python数据可视化之画图
2019/01/15 Python
python实现合并多个list及合并多个django QuerySet的方法示例
2019/06/11 Python
如何用Python 加密文件
2020/09/10 Python
Dogeared官网:在美国手工制作的珠宝
2019/08/24 全球购物
营销与策划应届生求职信
2013/11/04 职场文书
汽车技术服务英文求职信范文
2014/01/02 职场文书
六十大寿答谢词
2014/01/12 职场文书
出国导师推荐信
2014/01/16 职场文书
公务员培的训心得体会
2014/09/01 职场文书
挂靠协议书
2015/01/27 职场文书
2015年教务主任工作总结
2015/07/22 职场文书
2016大学生社会实践单位评语
2015/12/01 职场文书
Python selenium的这三种等待方式一定要会!
2021/06/10 Python
用Python将GIF动图分解成多张静态图片
2021/06/11 Python
win11无法登录onedrive错误代码0x8004def7怎么办 ?
2022/04/05 数码科技