要在地图上循环输出标记并给标记添加click事件,如果使用如下代码则所有标记被点击后infowindow输出的信息是一样的都是:考勤日期10,i 的值一直会是10
先看错误代码:
result = [...];//比如有10个数据
for(var i=0;i<result.length;i++){
var marker = new BMap.Marker(new BMap.Point(result[i].coordx, result[i].coordy));
var date = result[i].date;
marker.addEventListener("click", function(e){
var infoWindow = new BMap.InfoWindow("<p style='font-size:14px;'>考勤日期"+ i + "</p>");
this.openInfoWindow(infoWindow);
});
map.addOverlay(marker);
}
再看看正确的代码:
result = [...];
for(var i=0;i<result.length;i++){
var marker = new BMap.Marker(new BMap.Point(result[i].coordx, result[i].coordy));
var date = result[i].date;
(function(){
var index = i;
marker.addEventListener("click", function(e){
var infoWindow = new BMap.InfoWindow("<p style='font-size:14px;'>考勤日期"+ index + "</p>");
this.openInfoWindow(infoWindow);
});
})();
map.addOverlay(marker);
}
这里用到了js的一个特性:闭包,什么是闭包呢?可以参考http://hi.baidu.com/infol/item/edaef3d2b91eddfdca0c392b 这篇文章,讲的很详细。这里主要强调当看到闭包的时候,可以用对象的方式去理解。
接下来分析一下上面两段代码,主要用到两个概念(1)作用域(2)变量生命周期:
for 循环里面是一个作用域这里相当与外围作用域,通过marker.addEventListener绑定的事件函数里面也有个作用域,由于后一个作用域里面引用了前一个作用域里声名的变量,导致循环完成后 i 没有被释放,一直存在于内存中。当我们触发单击事件的时候,循环早已经完成,此时的 i 的值是10。所以才会发生所有Infowindow的值都是:考勤日期10
第二段代码里把事件函数用(function(){...});匿名函数包围起来,相当于增加了一层作用域,我们知道匿名函数外面加括号相当于一个表达式,而表达式里面声名的变量在表达式结束后就释放了,所以能够取到正确的值。