javascript 数组和对象赋值的坑

前两天在用vuejs给公司网站写东西的时候,需要对数组进行赋值,然后就发现了个奇怪的现象,赋值后的数组会随着之前给它赋值的数组的变化而变化,然后就不淡定了,意识到可能是等号直接把内存指向也一并赋值了,所以,这个赋值遇到数组和对象的时候,一定要三思,我就查了下,并且记录一下,希望以后不会犯这种错误。

傻傻分不清楚的赋值

demo1

1
2
3
4
var one = "girl";
var two = one;
one = "boy";
console.log(two);

大家猜猜结果吧,结果two没变,还是个”girl”。

demo2

1
2
3
4
var one = {sex:"girl"};
var two = one;
one = {sex:"boy"};
console.log(two);

哇塞,结果two也是没变,还是个”girl”。

demo3

1
2
3
4
var one = {sex:"girl"};
var two = one;
one.sex = "boy";
console.log(two);

完了,变了,变成”boy”了。

demo4

1
2
3
4
var one = [{sex:"girl"}];
var two = one;
one = [{sex:"boy"}];
console.log(two);

没有变哦,跟上面的demo2很像。

demo5

1
2
3
4
var one = [{sex:"girl"}];
var two = one;
one[0].sex = "boy";
console.log(two);

数组也是幸免不了的变了,跟上面的demo3很像。

原理

ECMAScript的变量值类型分为两种:
基本类型-包括Undefined, Null, Boolean, Number和String
引用类型-保存在内存中的对象们,不能直接操作,只能通过保存在变量中的地址引用对其进行操作

变量赋值时总是会copy一份的,如果是基本类型,copy的就是实际的值,如果是引用类型,copy的是指向Object的地址值,所以指向的还是同一个Object。

但是上例中的demo2和demo4是没变的,为啥呢,因为one又创建了一个新的地址空间,two指向的还是旧的one的地址空间,所以one没有改变。

1
2
3
4
5
6
7
var a = "boy";
var b = "boy";
console.log(a == b); // true

var one = ["boy"];
var two = ["boy"];
console.log(one == two); // false

对于基本类型,比较的就是实际的值,而对于引用类型,比较的是地址值。

如何避免这种问题

避免的原理就是再创建一个新的对象,来避免重复的地址引用。

利用jQuery的$.extend()

1
2
3
4
5
6
var x = {
one: "boy",
two: {sex:"boy"},
three: ["boy","girl"]
}
var y = $.extend(true, {}, x);

这时,无论x怎么改,y都是原来的x。

利用 JSON 全局对象

1
2
3
4
5
6
var x = {
one: "boy",
two: {sex:"boy"},
three: ["boy","girl"]
}
var y = JSON.parse(JSON.stringify(x));

对于数组

利用数组的splice方法
1
2
var a = [1,2,3,4,5];
var b = a.splice(0);
利用数组的map方法
1
2
3
4
var a = [1,2,3,4,5];
var b = a.map(function(res) {
return res;
});
坚持原创技术分享,您的支持将鼓励我继续创作!