数组的浅拷贝

  如果是数组,我们可以利用数组的一些方法比如:slice、concat 返回一个新数组的特性来实现拷贝。比如:

var arr = ['old', , true, null, undefined];
var new_arr = arr.concat();
new_arr[] = 'new';
console.log(arr) // ["old", 1, true, null, undefined]
console.log(new_arr) // ["new", 1, true, null, undefined]
var arr = ['old', , true, null, undefined];
var new_arr = arr.slice();
new_arr[] = 'new';
console.log(arr) // ["old", 1, true, null, undefined]
console.log(new_arr) // ["new", 1, true, null, undefined]

  concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本,即返回一个新的数组。语法:arrayObject.concat(arrayX,......,arrayX),该数组是通过把所有 arrayX 参数添加到 arrayObject 中生成的。如果要进行 concat() 操作的参数是数组,那么添加的是数组中的元素,而不是数组

  slice() 方法从已有的数组中返回选定的元素。语法:arrayObject.slice(start,end),返回一个新的数组,包含从 start 到 end (不包括该元素)的 arrayObject 中的元素。请注意,该方法并不会修改数组,而是返回一个子数组。如果想删除数组中的一段元素,应该使用方法 Array.splice()。

  注释:1、您可使用负值从数组的尾部选取元素。2、如果 end 未被规定,那么 slice() 方法会选取从 start 到数组结尾的所有元素。

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

var arr = [{old: 'old'}, ['old']];
var new_arr = arr.concat();
arr[].old = 'new';
arr[][] = 'new';
console.log(arr) // [{old: 'new'}, ['new']]
console.log(new_arr) // [{old: 'new'}, ['new']]

  我们会发现,无论是新数组还是旧数组都发生了变化,也就是说使用 concat 方法,克隆的并不彻底。这里可以联系之前写的值传递和引用传递、栈内存和堆内存的问题:如果数组元素是基本类型,就会拷贝一份,互不影响,而如果是对象或者数组,就会只拷贝对象和数组的引用,这样我们无论在新旧数组进行了修改,两者都会发生变化

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

数组的深拷贝

  那如何深拷贝一个数组呢?这里介绍一个技巧,不仅适用于数组还适用于对象!那就是:

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

  是一个简单粗暴的好方法,就是有一个问题,不能拷贝函数,我们做个试验:

浅拷贝的实现

  以上三个方法 concat、slice、JSON.stringify 都算是技巧类,可以根据实际项目情况选择使用,接下来我们思考下如何实现一个对象或者数组的浅拷贝。

  想一想,好像很简单,遍历对象,然后把属性和属性值都放在一个新的对象不就好了~嗯,就是这么简单,注意几个小点就可以了:

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 arr = [{old:"old"},["old"]];
var newarr = shallowCopy(arr);
console.log(newarr);//[{old:"new"},["old"]]
newarr[].old = 'new';
console.log(arr,newarr);//[{old:"new"},["old"]], [{old:"new"},["old"]]

深拷贝的实现

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

var deepCopy = function(obj) {
// 只拷贝对象
if (typeof obj !== 'object') return;
// 根据obj的类型判断是新建一个数组还是对象
var newObj = obj instanceof Array ? [] : {};
// 遍历obj,并且判断是obj的属性才拷贝
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
/* if(typeof obj[key] === "object"){
newObj[key] = deepCopy(obj[key]);
}else{
newObj[key] = obj[key];
}
*/
newObj[key] = typeof obj[key] === "object" ?
deepCopy(obj[key]) : obj[key]
}
}
return newObj;
}
var arr = [{old:"old"},["old"]];
var newarr = deepCopy(arr);
console.log(newarr);//[{old:"new"},["new"]]
newarr[].old = 'new';
newarr[][] = 'new';
console.log(arr,newarr);//[{old:"old"},["old"]],[{old:"new"},["new"]]

性能问题

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

JavaScript之深浅拷贝的更多相关文章

  1. javascript实现深浅拷贝

    深浅拷贝通常是对于引用数据类型进行的(数据类型为:对象(Object).数组(Array).函数(Function)) 浅拷贝: let obj = {id: 1, name: 2}; let new ...

  2. javascript简单实现深浅拷贝

    深浅拷贝知识在我们的日常开发中还算是用的比较多,但是之前的状态一直都是只曾听闻,未曾使用(其实用了只是自己没有意识到),所以今天来跟大家聊一聊js的深浅拷贝: 首先我们来了解一下javascript的 ...

  3. JavaScript深浅拷贝区别

    分享一篇自己关注的微信订阅号(前端大全)文章:JavaScript浅拷贝与深拷贝 作者:浪里行舟 https://github.com/ljianshu/Blog/issues/5 这里很详细的讲解了 ...

  4. JavaScript数据存储和深浅拷贝实际运用

    JavaScript分两种数据类型.1.简单数据类型有:number, string, boolean, undefined和null当声明一个简单数据类型的变量时,在内存中会把数据存在栈里.2.复杂 ...

  5. JavaScript中的事件委托机制跟深浅拷贝

    今天聊下JavaScript中的事件委托跟深浅拷贝 事件委托 首先呢,介绍一下事件绑定 //方法一:通过onclick <button onclick="clickEvent()&qu ...

  6. JavaScript深浅拷贝

    深浅拷贝 基本类型和引用类型 ECMAScript 中的变量类型分为两类: 基本类型:undefined,null,布尔值(Boolean),字符串(String),数值(Number) 引用类型: ...

  7. Javascript 中的深浅拷贝

    工作中经常会遇到需要复制 JS 数据的时候,遇到 bug 时实在令人头疼:面试中也经常会被问到如何实现一个数据的深浅拷贝,但是你对其中的原理清晰吗?一起来看一下吧! 为什么会有深浅拷贝 想要更加透彻的 ...

  8. JavaScript中的深浅拷贝

    深浅拷贝 在JS中,数据类型分为两类: ​ 简单数据类型:Number.Boolean.String.undefined ​ 引用数据类型:Array.Object.Function 简单数据类型通常 ...

  9. Python开发【第二章】:Python深浅拷贝剖析

    Python深浅拷贝剖析 Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果. 下面本文就通过简单的例子介绍一下这些概念之间的差别. 一.对象赋值 ...

随机推荐

  1. JAVAEE——宜立方商城04:图片服务器FastDFS、富文本编辑器KindEditor、商品添加功能完成

    1. 学习计划 1.图片上传 a) 图片服务器FastDFS b) 图片上传功能实现 2.富文本编辑器的使用KindEditor 3.商品添加功能完成 2. 图片服务器的安装 1.存储空间可扩展. 2 ...

  2. iOS 11开发教程(七)编写第一个iOS11代码Hello,World

    iOS 11开发教程(七)编写第一个iOS11代码Hello,World 代码就是用来实现某一特定的功能,而用计算机语言编写的命令序列的集合.现在就来通过代码在文本框中实现显示“Hello,World ...

  3. apache 监控

    当前加载模块 [root@controller01 ~]# httpd -lCompiled in modules: core.c mod_so.c http_core.c 当前版本[root@con ...

  4. python 列表的浅拷贝和深拷贝

    转自:https://www.cnblogs.com/laolibk/p/7821369.html 浅拷贝 shallow copy 和深拷贝 deep copy list.copy() 浅拷贝:复制 ...

  5. 解决在ubuntu环境下, sublime不能输入中文的问题

    sublime text很好用,但是ubuntu下不能输入中文,这是一个很大的问题.网上已经有很多方法,这里将我自己使用的方法记录总结一下 首先,将你的操作系统升级到最新版: sudo apt-get ...

  6. Reading lists for new LISA students(转)

    Research in General How to write a great research paper Basics of machine learning http://www.iro.um ...

  7. django中日志配置

    # ======日志配置====== # 错误优先级:NOTSET < DEBUG < INFO < WARNING < ERROR < CRITICAL # Djang ...

  8. BZOJ2673 [Wf2011]Chips Challenge 费用流 zkw费用流 网络流

    https://darkbzoj.cf/problem/2673 有一个芯片,芯片上有N*N(1≤N≤40)个插槽,可以在里面装零件. 有些插槽不能装零件,有些插槽必须装零件,剩下的插槽随意. 要求装 ...

  9. codevs 1191 树轴染色 线段树区间定值,求和

    codevs 1191 树轴染色 Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://www.codevs.cn/problem/1191/ Des ...

  10. Idea详细配置

    https://blog.csdn.net/m_m254282520/article/details/78900238