JavaScript数组和对象的复制

一、数据类型

从狭义上来说,JS把所有的数据分成两大类型:基本类型和引用类型,其中基本类型包括Undefined、Null、Boolean、Number和String,引用类型为Object,常用的Array、Date、RegExp、Function等都属于Object类型。

基本型数据和引用型数据的区别之一就是,在复制变量时,基本型数据复制独立的一份新的拷贝,而引用型数据复制的是原变量的引用。下面是一个例子:

rush:js;"> // 基本类型数据的复制 var a = 10; var b = a; // b = 10 a = 20; // a = 20,b = 10 // 引用类型数据的复制 var m = [1,2]; var n = m; m[0] = 10; console.log(n[0]); // 10

如果我想复制引用类型本身的值而非引用,显然不能采用上面的方式。

二、数组的浅复制

浅复制是指对象(数组)被复制时,其引用字段的值不会被复制,而是复制了对应字段的引用。如:

rush:js;"> var src = [ 'alpha',['bravo','chalie'] ]; var dest = []; for (var i = 0; i < src.length; i++) { dest[i] = src[i]; } //此时,如果改变src中的引用字段,dest中相应的字段也会被改变 src[1].push('delta'); console.log(dest[1]); // ['bravo','chalie','delta']

浅复制一般用于一维数组,即数组中不存在引用类型的情况。常用的浅复制方法有:

concat方法

rush:js;"> var src = ['alpha','bravo'],dest = []; dest = dest.concat(src);

concat方法更多地被用在数组合并中,比如:

rush:js;"> var a = ['alpha',b = ['chalie','delta'],combine; combine = a.concat(b);

特别要指出,concat用于数组合并时,是将两个(或多个)数组中的所有元素复制到新的对象,对于大型数组来说,开销比较大。更好的办法是把后一个数组的元素复制到前一个数组中:

rush:js;"> var src = ['alpha',dest = ['chalie','delta']; Array.prototype.push.apply(src,dest);

slice方法

slice方法可以从已有数组中返回选定的元素,返回的是一个新数组。

rush:js;"> var src = ['alpha',var dest = src.slice(0);

三、对象的浅复制

对象的浅复制可以用for-in遍历来实现,在es6中提供了更为方便的object.assign()方法

rush:js;"> var src = {name: 'fox',age: 20},dest = null; dest = Object.assign({},src);

也可以使用jQuery中的$.extend,underscore中的_.extend等方法来实现对象的复制。

四、深度复制

浅复制的应用场景有限,更多情况下,我们希望能够将对象复制出一个完整的副本,这就需要用到typeof或instanof操作符来对各个字段的类型进行判断。如果某字段是基本类型的,可以直接复制。如果某字段是引用类型的,还需要对该字段的所有字段进行上述判断,这就很容易让我们考虑使用递归来实现这个功能

rush:js;"> function deep_copy(src,dest) { for (var p in src) { if (Array.isArray(src[p]) || src[p] instanceof Object) { dest[p] = Array.isArray(src[p]) ? [] : {}; arguments.callee(dest[p],src[p]); }else { dest[p] = src[p]; } } }

在上述代码中,由于数组是特殊的对象,因此可以用for-in来遍历。

另外,还可以使用json大法:

rush:js;"> function deep_copy_in_json(src) { return JSON.parse(JSON.stringify(src)); }

这样做虽然比较简便,但原对象的很多属性在操作后会丢失,比如construtor属性以及对象原型中的一些方法

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持编程之家!

相关文章

前言 做过web项目开发的人对layer弹层组件肯定不陌生,作为l...
前言 前端表单校验是过滤无效数据、假数据、有毒数据的第一步...
前言 图片上传是web项目常见的需求,我基于之前的博客的代码...
前言 导出Excel文件这个功能,通常都是在后端实现返回前端一...
前言 众所周知,js是单线程的,从上往下,从左往右依次执行,...
前言 项目开发中,我们可能会碰到这样的需求:select标签,禁...