JS陷阱(一)

昨天晚上 龙龙酱 遇到了一个很有意思的JS问题,向 array 里面 push 数据,每次都会把数组里面的所有元素全部变成最后一次 push 的数据。大家首先想到的就是作用域问题,但是由于 龙龙酱 的代码规范不佳(好吧,我们水平也不行),愣是搞了一个多小时才找出原因。下面是把 龙龙酱 的代码简化后的复现代码

var temp_a = [];
temp_a['a'] = 0;
temp_a['b'] = 0;
var temp_array = [];

function arrayAdd() {
temp_a['a'] = parseInt(Math.random()*100);
temp_a['b'] = parseInt(Math.random()*100);

temp_array.push(temp_a);
print_temp_array();
}

function print_temp_array(){
for (var index = 0; index < temp_array.length; index++) {
var element = temp_array[index];
console.log('<'+element['a']+', '+element['b']+'>');
}
}

arrayAdd();
arrayAdd();
arrayAdd();
arrayAdd();

看了上面的代码,想必大家都能找出原因了吧。temp_a 是全局对象啊,往 array 里面 push 全局变量啊!!temp_a 还改来改去的!!!能不出问题嘛!!!!

发现问题后 龙龙酱 修改了arrayAdd函数,加了一行代码:

function arrayAdd() {
temp_a = [];// 龙龙酱增加了这行代码
temp_a['a'] = parseInt(Math.random()*100);
temp_a['b'] = parseInt(Math.random()*100);

temp_array.push(temp_a);
print_temp_array();
}

解决了问题了。。。

其实这是 JavaScript 垃圾回收机制所导致的问题,array 的 push 操作实际上是保存的 object 的引用,并且对 object 的内存引用加一,但是 temp_a 依然指向这个 object,修改这个 object 也就等于修改了 array 里面的值。所以每次修改temp_a 都会导致 array 里面的所有元素的值都变化。

龙龙酱 加的一行代码的作用就是每次都重新创建一个temp_a,由于之前的 object 依然被 array 引用着,所以这里即使对temp_atemp_a = null操作,之前的 object 也不会被释放。而每次重新创建 object 赋值给temp_a,也就相当于每次向 array 里面 push 的都是新的 object 了。

PS:以上代码是本人尽量按照 龙龙酱 的代码风格写的简化版,不代表个人的代码风格 😜