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 学习之二 属性(类)
Nov 25 Javascript
关于用Jquery的height()、width()计算动态插入的IMG标签的宽高的问题
Dec 08 Javascript
jQuery 源码分析笔记(3) Deferred机制
Jun 19 Javascript
jQuery控制iFrame(实例代码)
Nov 19 Javascript
js/jquery获取文本框输入焦点的方法
Mar 04 Javascript
jQuery插件imgPreviewQs实现上传图片预览
Jan 15 Javascript
bootstrap按钮插件(Button)使用方法解析
Jan 13 Javascript
详解vue项目构建与实战
Jun 27 Javascript
无限循环轮播图之运动框架(原生JS实现)
Oct 01 Javascript
使用JS模拟锚点跳转的实例
Feb 01 Javascript
vue项目中使用particles实现粒子背景效果及遇到的坑(按钮没有点击响应)
Feb 11 Javascript
vue.js Router中嵌套路由的实用示例
Jun 27 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
php中$_SERVER[PHP_SELF] 和 $_SERVER[SCRIPT_NAME]之间的区别
2009/09/05 PHP
php生成xml简单实例代码
2009/12/16 PHP
PHP 抽象方法与抽象类abstract关键字介绍及应用
2014/10/16 PHP
PHP获得数组交集与差集的方法
2015/06/10 PHP
PHP实现下载远程图片保存到本地的方法
2017/06/19 PHP
jquery下组织javascript代码(js函数化)
2010/08/25 Javascript
JQuery 应用 JQuery.groupTable.js
2010/12/15 Javascript
2012年开发人员的16款新鲜的jquery插件体验分享
2012/12/28 Javascript
一个封装js代码-----展开收起效果示例
2013/07/03 Javascript
自定义ExtJS控件之下拉树和下拉表格附源码
2013/10/15 Javascript
JQuery操作iframe父页面与子页面的元素与方法(实例讲解)
2013/11/20 Javascript
jQuery实现的类似淘宝网站搜索框样式代码分享
2015/08/24 Javascript
jQuery使用animate实现ul列表项相互飘动效果示例
2016/09/16 Javascript
WEB开发之注册页面验证码倒计时代码的实现
2016/12/15 Javascript
JavaScript正则表达式替换字符串中图片地址(img src)的方法
2017/01/13 Javascript
基于ajax和jsonp的原生封装(实例)
2017/10/16 Javascript
解决vue中监听input只能输入数字及英文或者其他情况的问题
2018/08/30 Javascript
使用vue2.6实现抖音【时间轮盘】屏保效果附源码
2019/04/24 Javascript
如何使用JavaScript检测空闲的浏览器选项卡
2020/05/28 Javascript
python算法学习之基数排序实例
2013/12/18 Python
理解生产者消费者模型及在Python编程中的运用实例
2016/06/26 Python
Python实现嵌套列表及字典并按某一元素去重复功能示例
2017/11/30 Python
Python使用pip安装报错:is not a supported wheel on this platform的解决方法
2018/01/23 Python
Flask框架模板继承实现方法分析
2019/07/31 Python
Python 爬虫实现增加播客访问量的方法实现
2019/10/31 Python
如何基于Python批量下载音乐
2019/11/11 Python
Python如何使用BeautifulSoup爬取网页信息
2019/11/26 Python
TENSORFLOW变量作用域(VARIABLE SCOPE)
2020/01/10 Python
python实现的分层随机抽样案例
2020/02/25 Python
解决django FileFIELD的编码问题
2020/03/30 Python
详解html5页面 rem 布局适配方法
2018/01/12 HTML / CSS
亚历山大·王官网:Alexander Wang
2017/06/23 全球购物
《两只鸟蛋》教学反思
2014/02/10 职场文书
实习公司领导推荐函
2014/05/21 职场文书
2014年法务工作总结
2014/12/11 职场文书
英文版辞职信
2015/02/28 职场文书