死亡是一座永恒的灯塔

0%

如何实现数组深拷贝和浅拷贝?

在使用JavaScript对数组进行操作的时候,我们经常需要将数组进行备份,事实证明如果只是简单的将它赋予其他变量,那么我们只要更改其中的任何一个,然后其它的也会跟着改变,这就导致了问题的发生。原因是内存中仅保留一份数据。这时候需要制作一份数据的副本。只有复杂类型变量(引用类型)存在深拷贝与浅拷贝的问题,而基本类型没有深拷贝的概念。

“堆内存”和“栈内存”

首先JavaScript中的变量分为基本类型和引用类型。基本类型就是保存在栈内存中的简单数据段,而引用类型指的是那些保存在堆内存中的对象。

基本类型

基本类型有Undefined、Null、Boolean、Number 和String。这些类型在内存中分别占有固定大小的空间,他们的值保存在栈空间,我们通过按值来访问的。

引用类型

引用类型,值大小不固定,栈内存中存放地址指向堆内存中的对象。是按引用访问的。栈内存中存放的只是该对象的访问地址,在堆内存中为这个值分配空间。由于这种值的大小不固定,因此不能把它们保存到栈内存中。但内存地址大小的固定的,因此可以将内存地址保存在栈内存中。这样,当查询引用类型的变量时,先从栈中读取内存地址, 然后再通过地址找到堆中的值。对于这种,我们把它叫做按引用访问。

当我们看到一个变量类型是已知的,就分配在栈里面,比如INT,Double等。其他未知的类型,比如自定义的类型,因为系统不知道需要多大,所以程序自己申请,这样就分配在堆里面。

JS数组的浅拷贝

简单的赋值就是浅拷贝。因为对象和数组在赋值的时候都是引用传递。赋值的时候只是传递一个指针。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var a = [1,2,3];

var b =a ;

var test = {name:'xiaohong', age:15};

var c = test;

console.log(a,b);

console.log(test);

console.log('-------------------');

b[0] =5;

c.age = 16;

console.log(a,b);

console.log(test);

console.log(c);

浅拷贝很容易,但是很多时候我们需要原样的把数组或者对象复制一份,在修改值的时候,不改变初始对象的值。这个时候就需要使用深拷贝。

JS数组的深拷贝

js的slice函数

slice() 方法可从已有的数组中返回选定的元素。

【语法】arrayObject.slice(start,end)

【参数】arrayObj–必选项:一个Array对象。start–必选项:arrayObj中所指定的部分的开始元素是从零开始计算的下标。end–可选项:arrayObj中所指定的部分的结束元素是从零开始计算的下标。

【说明】

slice 方法返回一个Array对象,其中包含了arrayObj的指定部分。slice方法一直复制到end所指定的元素,但是不包括该元素。如果start为负,将它作为length + start处理,此处length为数组的长度。如果end为负,就将它作为length + end处理,此处length为数组的长度。如果省略end ,那么slice方法将一直复制到 arrayObj 的结尾。如果end出现在start之前,不复制任何元素到新数组中。

实例:

1
2
3
4
5
6
7
8
9
var a = [1,2,3,4,5];

var b = a.slice(0,2);

var c = a.slice(-3,-1);

var d = a.slice(-1,-3);

console.log(b,c,d);

js的concat函数

concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。

【语法】arrayObject.concat(arrayX,arrayX,……,arrayX)

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

【说明】

返回一个新的数组。该数组是通过把所有 arrayX 参数添加到 arrayObject 中生成的。如果要进行 concat()操作的参数是数组,那么添加的是数组中的元素,而不是数组。

实例:

1
2
3
4
5
6
7
8
9
10
11
var a = [1,2,3];

var b = a.concat(4,5);

console.log(b);

var c = [6,7];

var d = a.concat(c);

console.log(d);

\

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27



## js遍历数组的方法

js遍历数组的方法

```javascript
var a = [1,2,3];

var b = [];

function deepCopy(arry1,arry2) {

for(i=0;i < arry1.length;i++) {

arry2[i] = arry1[i];

}

}

deepCopy(a,b);

a[0] = "A";

console.log(a,b);

slice()、concat()的局限性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var a = [1,2,{"name":"张三"},{"name":"李四"},[4,5]];

var b = a.slice(0);

var c = [].concat(a);

a[2].name="王五";

a = "A";

console.log(a);

console.log(b);

console.log(c);

由上面的例子可以看出,由于数组内部存在对象和数组,当改变对象属性和内部数组的元素后,深拷贝的b和c同样也发生了改变。因此,slice和concat这两个方法,仅适用于对不包含引用对象的一维数组的深拷贝。

坚持技术分享,您的支持将鼓励我继续创作!