博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JavaScript系列--深浅拷贝简单实现
阅读量:7300 次
发布时间:2019-06-30

本文共 2560 字,大约阅读时间需要 8 分钟。

一、前言

之前写了一篇:浅析JavaScript解析赋值、浅拷贝和深拷贝的区别: 里面介绍了解析赋值,浅拷贝,深拷贝的原理和实现。浅拷贝方法:Object.assign(),展开语法Spread,Array.prototype.alice(),array.prototype.concat()。深拷贝方法:JSON.parse(JSON.stringify(object)),对于undefined,symbol和函数的会直接忽略。

javascript之Object.assign实现浅拷贝的原理以及实现:

二、数组浅拷贝

如果是数组,可以使用数组的一些方法实现:slice(),concat()返回一个新数组的特性实现拷贝。

举个例子:

用concat()实现

var arr = ['saucxs', 1, true, null, undefined];var new_arr = arr.concat();new_arr[0] = 'new';console.log(arr) // ["saucxs", 1, true, null, undefined]console.log(new_arr) // ["new", 1, true, null, undefined]复制代码

用slice实现

var new_arr = arr.slice();复制代码

但是如果数组嵌套了对象或者数组的话,比如:

var arr = [{old: 'old'}, ['old']];var new_arr = arr.concat();arr[0].old = 'new';arr[1][0] = 'new';console.log(arr) // [{old: 'new'}, ['new']]console.log(new_arr) // [{old: 'new'}, ['new']]复制代码

发现:无论是新数组还是旧数组都发生了变化,也就是说使用 concat 方法,克隆的并不彻底

用扩展运算符spread实现

var arr = [{old: 'old'}, ['old']];var new_arr =[...arr];arr[0].old = 'new';arr[1][0] = 'new';console.log(arr) // [{old: 'new'}, ['new']]console.log(new_arr) // [{old: 'new'}, ['new']]复制代码

总结:

如果数组元素是基本类型,就会拷贝一份,互不影响,而如果是对象或者数组,就会只拷贝对象和数组的引用,这样我们无论在新旧数组进行了修改,两者都会发生变化。

我们把这种复制引用的拷贝方法称之为浅拷贝,与之对应的就是深拷贝,深拷贝就是指完全的拷贝一个对象,即使嵌套了对象,两者也相互分离,修改一个对象的属性,也不会影响另一个。

所以我们可以看出使用 concat , slice, 扩展预算符spread 是一种浅拷贝。

三、数组深拷贝

JSON.parse(JSON.stringify())不仅适用于数组还适用于对象。

var arr = ['old', 1, true, ['old1', 'old2'], {old: 1}]var new_arr = JSON.parse( JSON.stringify(arr) );console.log(new_arr);复制代码

这个方法是一个简单粗暴的好方法,就是有一个问题,不能拷贝函数,undefined,symbol。

我们举个例子看一下:

var arr = [    function(){ console.log(a)},     { b: function(){ console.log(b)}},    undefined,    Symbol('saucxs')]var new_arr = JSON.parse(JSON.stringify(arr));console.log(new_arr);   //[null, {}, null, null]复制代码

四、浅拷贝的实现

接下来我们思考下如何实现一个对象或者数组的浅拷贝。

想一想,好像很简单,遍历对象,然后把属性和属性值都放在一个新的对象里。

var shallowCopy = function(obj) {    // 只拷贝对象    if (typeof obj !== 'object') return;    // 根据obj的类型判断是新建一个数组还是对象    var newObj = obj instanceof Array ? [] : {};    // 遍历obj,并且判断是obj的属性才拷贝    for (var key in obj) {        if (obj.hasOwnProperty(key)) {            newObj[key] = obj[key];        }    }    return newObj;}复制代码

五、深拷贝的实现

如何实现一个深拷贝呢?说起来也好简单,我们在拷贝的时候判断一下属性值的类型,如果是对象,我们递归调用深拷贝函数不就好。

var deepCopy = function(obj) {    if (typeof obj !== 'object') return;    var newObj = obj instanceof Array ? [] : {};    for (var key in obj) {        if (obj.hasOwnProperty(key)) {            newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];        }    }    return newObj;}复制代码

六、注意事项

尽管使用深拷贝会完全的克隆一个新对象,不会产生副作用,但是深拷贝因为使用递归,性能会不如浅拷贝,在开发中,还是要根据实际情况进行选择。

转载地址:http://etsnm.baihongyu.com/

你可能感兴趣的文章
超异类的“无用类”网站导航网站 - theuselessweb.com
查看>>
[置顶] Android仿人人客户端(v5.7.1)——应用主界面之左侧面板UI实现
查看>>
情况动态规划CodeForces Round #179 (296B) - Yaroslav and Two Strings
查看>>
配置Erlang shell的工作路径
查看>>
Unity Built-in Shader详解二
查看>>
[置顶] 使用sping AOP 操作日志管理
查看>>
QRadioButton类中Toggled()信号的使用方法
查看>>
权限管理之基于ACL的实现:自定义JSTL函数实现即时认证
查看>>
svn删除项目目录
查看>>
机器学习 —— 概率图模型(推理:连续时间模型)
查看>>
ODI Studio拓扑结构的创建与配置(Oracle)
查看>>
form、iframe实现异步上传文件
查看>>
获取Web.config配置节
查看>>
膝盖中了一箭之康复篇-第十个月暨4月份目标总结
查看>>
【swift学习笔记】一.页面转跳的条件判断和传值
查看>>
系统调用表 linux 2.6.32
查看>>
已经重写,源码和文章请跳转http://www.cnblogs.com/ymnets/p/5621706.html
查看>>
我对遗传算法理解
查看>>
论 <%@taglib prefix="s" uri="/struts-tags" %> 的重要性
查看>>
Java 日期 Api
查看>>