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中使用"with"语句中跨frame的变量引用问题
Mar 08 Javascript
JavaScript Event学习第十一章 按键的检测
Feb 10 Javascript
jQuery实现鼠标移到元素上动态提示消息框效果
Oct 20 Javascript
使用JS获取当前地理位置方法汇总
Dec 18 Javascript
JS实现3D图片旋转展示效果代码
Sep 22 Javascript
JS实现淡蓝色简洁竖向Tab点击切换效果
Oct 06 Javascript
学习JavaScript图片预加载模块
Nov 07 Javascript
vue表单绑定实现多选框和下拉列表的实例
Aug 12 Javascript
详解vue-cli 脚手架 安装
Apr 16 Javascript
javascript实现简易聊天室
Jul 12 Javascript
Angular8基础应用之表单及其验证
Aug 11 Javascript
jQuery冲突问题解决方法
Jan 19 jQuery
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
Extended CHM PHP 语法手册之 DIY
2006/10/09 PHP
php 伪造本地文件包含漏洞的代码
2011/11/03 PHP
cnblogs csdn 代码运行框实现代码
2009/11/02 Javascript
JQuery live函数
2010/12/24 Javascript
JavaScript使用IEEE 标准进行二进制浮点运算产生莫名错误的解决方法
2011/05/28 Javascript
Javascript模块化编程(一)AMD规范(规范使用模块)
2013/01/17 Javascript
JS Date函数整理方便使用
2013/10/23 Javascript
文档对象模型DOM通俗讲解
2013/11/01 Javascript
如何调试异步加载页面里包含的js文件
2014/10/30 Javascript
在父页面得到zTree已选中的节点的方法
2015/02/12 Javascript
JavaScript实现点击文字切换登录窗口的方法
2015/05/11 Javascript
AngularJS学习笔记之基本指令(init、repeat)
2015/06/16 Javascript
jquery实现鼠标经过显示下划线的渐变下拉菜单效果代码
2015/08/24 Javascript
jQuery插件FusionCharts实现的MSBar3D图效果示例【附demo源码】
2017/03/23 jQuery
jquery动态添加带有样式的HTML标签元素方法
2018/02/24 jQuery
微信公众平台获取access_token的方法步骤
2019/03/29 Javascript
教你搭建按需加载的Vue组件库(小结)
2019/07/29 Javascript
Node.js API详解之 assert模块用法实例分析
2020/05/26 Javascript
Vue页面跳转传递参数及接收方式
2020/09/09 Javascript
基于ajax实现上传图片代码示例解析
2020/12/03 Javascript
python实现bitmap数据结构详解
2014/02/17 Python
Python返回真假值(True or False)小技巧
2015/04/10 Python
Python配置文件解析模块ConfigParser使用实例
2015/04/13 Python
Python中list列表的一些进阶使用方法介绍
2015/08/15 Python
K-近邻算法的python实现代码分享
2017/12/09 Python
Python破解BiliBili滑块验证码的思路详解(完美避开人机识别)
2020/02/17 Python
使用layui实现左侧菜单栏及动态操作tab项的方法
2020/11/10 HTML / CSS
戴尔美国官网:Dell
2016/08/31 全球购物
Zadig&Voltaire官网:法国时装品牌
2018/01/05 全球购物
限量版运动鞋和街头服饰:TheDrop
2020/09/06 全球购物
学习标兵获奖感言
2014/02/20 职场文书
党员廉洁自律个人总结
2015/02/13 职场文书
股东大会通知
2015/04/24 职场文书
能用CSS实现的就不要麻烦JavaScript了
2021/10/05 HTML / CSS
Nginx 路由转发和反向代理location配置实现
2021/11/11 Servers
mysql timestamp比较查询遇到的坑及解决
2021/11/27 MySQL