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 相关文章推荐
用XMLDOM和ADODB.Stream实现base64编码解码实现代码
Nov 28 Javascript
javaScript同意等待代码实现心得
Jan 01 Javascript
jquery $.each()使用探讨
Sep 23 Javascript
js的alert样式如何更改如背景颜色
Jan 22 Javascript
Javascript基础教程之argument 详解
Jan 18 Javascript
微信小程序 textarea 详解及简单使用方法
Dec 05 Javascript
js+html5实现复制文字按钮
Jul 15 Javascript
js实现图片轮播效果学习笔记
Jul 26 Javascript
JS中使用textPath实现线条上的文字
Dec 25 Javascript
详解JavaScript中的数组合并方法和对象合并方法
May 11 Javascript
谈谈为什么你的 JavaScript 代码如此冗长
Jan 30 Javascript
js实现石头剪刀布游戏
Oct 11 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
ThinkPHP实现带验证码的文件上传功能实例
2014/11/01 PHP
php实现获取文章内容第一张图片的方法
2014/11/04 PHP
php使用str_replace实现输入框回车替换br的方法
2014/11/24 PHP
Zend Framework实现将session存储在memcache中的方法
2016/03/22 PHP
Apache PHP MySql安装配置图文教程
2016/08/27 PHP
PHP+Redis开发的书签案例实战详解
2019/07/09 PHP
laravel实现一个上传图片的接口,并建立软链接,访问图片的方法
2019/10/12 PHP
超棒的javascript页面顶部卷动广告效果
2007/12/01 Javascript
JavaScript DOM学习第六章 表单实例
2010/02/19 Javascript
jQuery html() in Firefox (uses .innerHTML) ignores DOM changes
2010/03/05 Javascript
jquery图片不完全按比例自动缩小的简单代码
2013/07/29 Javascript
jquery重新播放css动画所遇问题解决
2013/08/21 Javascript
自定义jquery模态窗口插件无法在顶层窗口显示问题
2014/05/29 Javascript
AMD异步模块定义介绍和Require.js中使用jQuery及jQuery插件的方法
2014/06/06 Javascript
解决Jquery向页面append新元素之后事件的绑定问题
2015/03/16 Javascript
浅谈JS正则表达式的RegExp对象和括号的使用
2016/07/28 Javascript
详解XMLHttpRequest(一)同步请求和异步请求
2016/09/14 Javascript
基于JSONP原理解析(推荐)
2017/12/04 Javascript
使用python实现正则匹配检索远端FTP目录下的文件
2015/03/25 Python
在Windows服务器下用Apache和mod_wsgi配置Python应用的教程
2015/05/06 Python
python语言中with as的用法使用详解
2018/02/23 Python
Python基于datetime或time模块分别获取当前时间戳的方法实例
2019/02/19 Python
详解Python利用random生成一个列表内的随机数
2019/08/21 Python
python实现扫雷小游戏
2020/04/24 Python
一文轻松掌握python语言命名规范规则
2020/06/18 Python
TensorFlow保存TensorBoard图像操作
2020/06/23 Python
如何通过python检查文件是否被占用
2020/12/18 Python
用HTML5.0制作网页的教程
2010/05/30 HTML / CSS
澳大利亚在线生活方式商店:Mytopia
2018/07/08 全球购物
SEPHORA丝芙兰德国官方购物网站:化妆品、护肤品和香水
2020/01/21 全球购物
幼儿园三八妇女节活动方案
2014/03/11 职场文书
文明市民先进事迹
2014/05/15 职场文书
机关作风建设心得体会
2014/10/22 职场文书
2016年学习贯彻十八届五中全会精神心得体会
2016/01/05 职场文书
妇联2016年六一国际儿童节活动总结
2016/04/06 职场文书
SpringBoot整合minio快速入门教程(代码示例)
2022/04/03 Java/Android