javascript数组拷贝及浅拷贝

今天在读阮一峰 ECMAScript6 中 数组扩展运算符中遇到一个问题——数组复制(拷贝),还涉及到浅拷贝,思考熟悉了下,特此记录。

文章目录

    • 1 数组复制
      • 1.1 ES5——concat()
      • 1.2 ES6——…运算符
      • 1.3 数组拷贝和直接用=等号区别
    • 2 浅拷贝

1 数组复制

1.1 ES5——concat()

在ES5 中我们可以使用concat函数变相实现数组复制

let a1 = [1, 2];
let a2 = a1.concat();
console.info(a2);//[ 1, 2 ]

1.2 ES6——…运算符

在ES6我们可以使用扩展运算符更加优雅的实现

let a1 = [1, 2];
let a2 = [...a1];//[ 1, 2 ]

1.3 数组拷贝和直接用=等号区别

    let a1 = [1, 2];
    let a2 = [...a1];
    console.info(a2);//[ 1, 2 ]
    let a3 = a1
    console.info(a3);//[ 1, 2 ]
    a1[0] = 3;
    console.info(a1);//[ 3, 2 ]
    console.info(a3);//[ 3, 2 ]
    console.info(a2);//[ 1, 2 ]

从这段代码就可以很明显的看出来a1 和 a3 实质上是指向的同一块数组,当a1改变时,a3 也会跟着改变。
但a2就不同了,a2相当于把a1数组中的内容(值)复制到a2数组中。

2 浅拷贝

因为上述的结果看到阮一峰说concat函数和…运算符均是浅复制,给出sample时还楞了一下,印象中的结果应该是1 中那种结果。

let a1 = [{ foo: 1 }];//[ { foo: 1 }, { bar: 2 } ]
let a2 = [{ bar: 2 }];
let a3 = a1.concat(a2);
console.info(a3);//[ { foo: 1 }, { bar: 2 } ]
a1[0].foo = 2  
console.info(a3);//[ { foo: 2 }, { bar: 2 } ]

不过后来一试,结果真变了,后面反应过来,耶 这个是对象耶,确实是浅复制。

这里就描述一下我理解的复制的行为,数组的复制均是对值的复制,这也就是通常所说的浅复制
1 对于String类型,number类型 即把值复制到新数组即完成了操作
2 但对于复合类型,如对象,数组等,复制行为复制的值均为指向该复合对象地址(可以理解成C语言中的指针,数组中存储复合类型本来就是存的复合类型的地址)。

所以上面结果就很号解释了,为什么改变a1中对象的值,会影响到a3,因为a3 和 a1中 那个对象均指向同一个地址。

我们可以下面一段code验证上面的说法:

let a1 = [{ foo: 1 }];
let a2 = [{ bar: 2 }];
let a3 = a1.concat(a2);
console.info(a1);//[ { foo: 1 } ]
console.info(a3);/[ { foo: 1 }, { bar: 2 } ]
a1[0].foo = 2     //修改对象中的内容
console.info(a1);//[ { foo: 2 } ]
console.info(a3);//[ { foo: 2 }, { bar: 2 } ]
a1[0] = {test:3}  //修改数组中的对象
console.info(a1);//[ { test: 3 } ]
console.info(a3);//[ { foo: 2 }, { bar: 2 } ]

可以看出直接把a1[0]换成一个新的对象,则a3就不会受到影响,因为a1[0]存储的对象地址已经和a3[0]中的存储的对象地址不一样了。

你可能感兴趣的:(javascript)