数组的浅拷贝

  如果是数组,我们可以利用数组的一些方法比如: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. 新一代数据库TiDB在美团的实践

    1. 背景和现状 近几年,基于MySQL构建的传统关系型数据库服务,已经很难支撑美团业务的爆发式增长,这就促使我们去探索更合理的数据存储方案和实践新的运维方式.而随着分布式数据库大放异彩,美团DBA团 ...

  2. [leetcode DP]91. Decode Ways

    A message containing letters from A-Z is being encoded to numbers using the following mapping: 'A' - ...

  3. 机器学习之路: tensorflow 自定义 损失函数

    git: https://github.com/linyi0604/MachineLearning/tree/master/07_tensorflow/ import tensorflow as tf ...

  4. 机器学习之路:python 字典特征提取器 DictVectorizer

    python3 学习使用api 将字典类型数据结构的样本,抽取特征,转化成向量形式 源码git: https://github.com/linyi0604/MachineLearning 代码: fr ...

  5. pip作用

    介绍 pip 是一个安装和管理 Python 包的工具,python安装包的工具有easy_install, setuptools, pip,distribute.使用这些工具都能下载并安装djang ...

  6. Python进阶篇:文件系统的操作

    通过一个例子来熟悉文件的基本操作:创建文件,读取文件,修改文件,删除文件,重命名文件,判断文件是否存在 ''' 编写可供查询的员工信息表--学号 姓名 年龄 班级 1. 提供格式化查询接口 2. 允许 ...

  7. ARC 101 D - Median of Medians

    题面在这里! 这种题只能二分答案把qwwq,直接做根本做不了啊... 首先你需要知道如何通过 一个区间<=x的数有多少个 来判断x和这个区间中位数的关系. 很显然当数有至少 [L/2]+1 个( ...

  8. HTML5区块和大纲算法

    原文链接: Using HTML sections and outlines - Mozilla Developer Network 每集HTML5+CSS3网页布局教程-2大纲算法 HTML5标准带 ...

  9. from setuptools import setup, find_packages ImportError: No module named set

    1 from setuptools import setup, find_packages ImportError: No module named set wget http://peak.tele ...

  10. hash课堂测试补分博客

    题目要求: 开放地址法: 概念: 所谓的开放定址法就是一旦发生了冲突,就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将记录存入. 它的公式为: 解题过程(在下图中): 拉链法: ...