拷贝分为浅拷贝和深拷贝,在JavaScript中能够实现这两种拷贝的方式也是多种多样。以下是一维数组实现深拷贝和浅拷贝的各种方式。

一、浅拷贝

1、赋值

赋值是最直接的一种浅拷贝。

let arr3 = [1,2,3]

let arr4 = arr3

arr4[0] = 11

console.log('arr3:',arr3); // [11,2,3]

2、copyWithin()方法——ES6新增

let arr3 = [1, 2, 3]

let arr4 = arr3.copyWithin(0,0)

arr4[0] = 11

console.log('修改arr4:', arr4); // 11,2,3

console.log('arr3:', arr3); // 11,2,3

二、深拷贝(针对一维纯值数组)

1、concat() 方法

concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。其参数可以是具体的值,也可以是数组对象。可以是任意多个。

arrayObject.concat(arrayX,arrayX,......,arrayX)

参数     描述

arrayX  必需。该参数可以是具体的值,也可以是数组对象。可以是任意多个。

利用concat()方法可以得到一个深拷贝的数组副本。

let arr3 = [1,2,3]

let arr4 = arr3.concat();

arr4[0] = 11

console.log('修改arr4:',arr4); //  11,2,3

console.log('arr3:',arr3);  // 1,2,3

2、slice()方法

slice() 方法可从已有的数组中返回选定的元素。返回一个新的数组,包含从 start 到 end (不包括该元素)的 arrayObject 中的元素。该方法并不会修改数组,而是返回一个子数组。

arrayObject.slice(start,end)

参数     描述

start      必需。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1 指最后一个元素,-2 指倒数第二个元素,以此类推。

end 可选。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。

利用slice()方法可以得到一个深拷贝的数组副本。

let arr3 = [1,2,3]

let arr4 = arr3.slice()

arr4[0] = 11

console.log('修改arr4:',arr4); // 11,2,3

console.log('arr3:',arr3);  // 1,2,3

3、序列化和反序列化方法

利用JSON.parse和JSON.stringify组合得到一个深拷贝的数组副本。

let arr3 = [1,2,3]

let arr4 = JSON.parse(JSON.stringify(arr3))

arr4[0] = 11

console.log('修改arr4:',arr4); // 11,2,3

console.log('arr3:',arr3);  // 1,2,3

注:此方法适用于Oject的深度拷贝,因为Array属于Oject类型,所以也适用于此处;需要注意的是:作为Oject的深度拷贝时,要复制的function会直接消失,所以这个方法只能用在单纯只有数据的对象。

4、扩展运算符——ES6新增

ES6新增的扩展运算符可以方便的实现数组的深拷贝(克隆)。

let arr3 = [1,2,3]

let arr4 = [...arr3]

arr4[0] = 11

console.log('修改arr4:',arr4);   // 11,2,3

console.log('arr3:',arr3);   // 1,2,3

let arr3 = [1,2,3]

let [...arr4] = arr3

arr4[0] = 11

console.log('修改arr4:',arr4);

console.log('arr3:',arr3);

5、Array.from——ES6新增

let arr1 = [1,2,3]

let arr2 = Array.from(arr1)

arr2[0] = 11

console.log('修改learr2');

console.log('arr1是否变化',arr1); // 验证结果:Array.from返回的是一个深度拷贝数组

6、map()方法

map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。

map() 方法按照原始数组元素顺序依次处理元素。

注意: map() 不会对空数组进行检测。 map() 不会改变原始数组。

array.map(function(currentValue,index,arr), thisValue)

参数     描述

function(currentValue, index,arr)   必须。函数,数组中的每个元素都会执行这个函数

函数参数:

参数     描述

currentValue      必须。当前元素的值

index    可选。当前元素的索引值

arr  可选。当前元素属于的数组对象

thisValue     可选。对象作为该执行回调时使用,传递给函数,用作 "this" 的值。

如果省略了 thisValue,或者传入 null、undefined,那么回调函数的 this 为全局对象。

let arr3 = [1,2,3]

let arr4 = arr3.map(item => item)

arr4[0] = 11

console.log('修改arr4:',arr4);  // 11,2,3

console.log('arr3:',arr3);  // 1,2,3

7、Object.assign()方法——ES6新增

Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。

let arr3 = [1,2,3]

let arr4 = []

Object.assign(arr4,arr3)

arr4[0] = 11

console.log('修改arr4:',arr4); // 11,2,3

console.log('arr3:',arr3);   // 1,2,3

注意:Object.assign()方法实行的是浅拷贝,而不是深拷贝。如果数组中的项是一个对象,那么目标数组中的该项拷贝得到的是这个对象的引用。

let arr3 = [{name:'aaa'},2,3]

let arr4 = []

Object.assign(arr4,arr3)

arr4[0].name = 11

console.log('修改arr4:',arr4);  // {name:11},2,3

console.log('arr3:',arr3);  // {name:11},2,3

8、扩展原型链

Array.prototype.clone = function () {

let arr = []

for (let i = 0, len = this.length; i < len; i++) {

arr.push(this[i])

}

return arr

}

let arr3 = [1, 2, 3]

let arr4 = arr3.clone()

arr4[0] = 11

console.log('修改arr4:', arr4); // 11,2,3

console.log('arr3:', arr3);  // 1,2,3

9、filter方法

filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。

注意: filter() 不会对空数组进行检测。filter() 不会改变原始数组。

array.filter(function(currentValue,index,arr), thisValue)

参数     描述

function(currentValue, index,arr)   必须。函数,数组中的每个元素都会执行这个函数。返回true表示保留该元素(通过测试),false则不保留

函数参数:

参数     描述

currentValue      必须。当前元素的值

index    可选。当前元素的索引值

arr  可选。当前元素属于的数组对象

thisValue     可选。对象作为该执行回调时使用,传递给函数,用作 "this" 的值。

如果省略了 thisValue ,"this" 的值为 "undefined"

返回值:返回数组,包含了符合条件的所有元素。如果没有符合条件的元素则返回空数组。

let arr3 = [1, 2, 3]

let arr4 = arr3.filter(item => true)

arr4[0] = 11

console.log('修改arr4:', arr4); // 11,2,3

console.log('arr3:', arr3);  // 1,2,3

总结

以上各种深拷贝方式只针对一维并且每一项值为数值和字符串的数组。多维数组或者一维但包含对象的数组除了第三种方式外,其他方式并不能实行深拷贝,实行的是浅拷贝。

三、多维数组的深拷贝

function deepcopy(obj) {

let out = [],len = obj.length;

for (let i = 0; i < len; i++) {

if (obj[i] instanceof Array){

out[i] = deepcopy(obj[i]);

} else {

out[i] = obj[i];

}

}

return out;

}

另一种方式:采用上面的第三种方式:序列化和反序列化结合实现。

前端学习笔记系列一:9 js中数组的拷贝的更多相关文章

  1. 前端学习笔记系列一:12 js中获取时间new date()的用法

    获取时间: 1  var myDate = new Date();//获取系统当前时间 获取特定格式的时间: 1 myDate.getYear(); //获取当前年份(2位) 2 myDate.get ...

  2. Javascript高级编程学习笔记(3)—— JS中的数据类型(1)

    前一段时间由于事情比较多,所以笔记耽搁了一段时间,从这一篇开始我会尽快写完这个系列. 文章中有什么不足之处,还望各位大佬指出. JS中的数据类型 上一篇中我写了有关JS引入的Script标签相关的东西 ...

  3. Javascript高级编程学习笔记(4)—— JS中的数据类型(2)

    接着昨天的文章,今天这篇文章主要讲述JS中剩余的两种数据类型String,和Object String类型 对于该类型,书中给出的解释为:由0或多个16为Unicode字符组成的字符序列. 对于JS中 ...

  4. 【学习笔记】彻底理解JS中的this

    首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象(这句话有些问题,后面会解释为什么会有问题,虽然 ...

  5. 前端学习笔记系列一:13new Date()的参数

    前两天发现手机页面的倒计时在Android上正常显示,在iPhone却不能显示. 后来又发现在ff和ie里也不显示.(以前只在chrome里看过,显示正常). 后来同事改了new Date()里字符串 ...

  6. JS中数组的拷贝方法

    之前在写一个vue的计算属性时,大概是这样: computed: { updateList () { let newList = this.List /*do something*/ return n ...

  7. 前端学习笔记系列一:5 在项目中引入阿里图标icon

    进入到阿里的图标库网站,里面有上百万种icon,https://www.iconfont.cn,需要注册一个帐号,然后进入到这个页面,在这里点击右下角的带加号的图标,创建一个新的项目,名称与你要使用图 ...

  8. 前端学习笔记系列一:11@vue/cli3.x中实现跨域的问题

    由于浏览器的同源访问策略,vue开发时前端服务器通常与后端api服务器并非是相同的服务器,因此需要使用一个代理服务器实现跨域访问.在@vue/cli3.x根目录下创建一个vue.config.js文件 ...

  9. 前端学习笔记系列一:10整体移动vscode代码块、VSCode 使用 stylus,配置格式化设置、在vue项目中引入bootstrap

    1.整体移动vscode代码块 凭借操作的经验我们能够轻松地知道将代码整体往右移只需选中代码按Tab键即可.其实往左移也很简单: 选中之后按下 shift+Tab键 即可. 2.VSCode 使用 s ...

随机推荐

  1. C++11特性中的stoi、stod

    本文摘录柳神笔记:   使⽤ stoi . stod 可以将字符串 string 转化为对应的 int 型. double 型变量,这在字符串处理的很 多问题中很有帮助-以下是示例代码和⾮法输⼊的处理 ...

  2. 【 hibernate 】基本配置

    hibernate.cfg.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibe ...

  3. hyfhaha大事记——luogu

    成就墙 AK CSP-J 初赛 AK CSP-J 复赛 CSP- J 一等奖 CSP-S 一等奖 大事记 2017-09-20 13:54 注册洛谷账号 之后洛谷一直处于沉沦状态 2018 2018- ...

  4. asp.net core配置下载文件

    asp.net core的wwwroot文件夹下默认时保存静态文件的地方,外面可以直接访问,但是如果是一些无法识别的后缀文件,如(.apk),会报错404 如果想要实现下载这些文件,在配置静态文件中间 ...

  5. 吴裕雄--天生自然ORACLE数据库学习笔记:SQL语言基础

    select empno,ename,sal from scott.emp; SELECT empno,ename,sal FROM scott.emp; selECT empno,ename,sal ...

  6. Duilib程序添加托盘图标显示

    转载:https://www.zhaokeli.com/article/8266.html 温馨提示:技术类文章有它的时效性,请留意文章更新时间以及软件的版本 功能描述 实现点击关闭后,程序最小化到托 ...

  7. JNDI Java 命名与目录接口

    jsp <% Context ctx = new InitialContext(); String jndiName = (String) ctx.lookup("java:comp/ ...

  8. 37 java序列化与反序列化

    一.java序列化与反序列化 1.序列化: 是指把java对象转换为字节序列的过程: 2.反序列化:是指把字节序列恢复为java对象的过程. 二.为什么要序列化 我们知道,当两个进程进行远程通信时,可 ...

  9. free to monitor your sqlserver easy and safe and ...

    Unlike AWR in Oracle, Sqlserver does not have offical way to make history performance information fo ...

  10. 图片的onload事件与better-scroll结合[ 当fastclick插件和better-scroll发生冲突导致点击事件失效时,可以给需要点击的元素加一个class="needsclick"]

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...