问题描述:做项目的时候用ajax请求从后台获取数据,根据获取到的数据在地图上循环建立marker标记。在给创建的marker添加点击事件的时候发现只能给最后一个创建的marker添加成功,尝试了几种方法,最终发现原因是data[index]在内函数中使用时不是每次循环都能取到当前的index,最后使用闭包函数解决的,写起来倒是很简单,我觉得这种东西以后会经常用到,记录一下供日后查阅。顺便学习了一下闭包函数。
错误的写法:
$.ajax({
...
success:function(data){
for(var index in data){
//循环创建marker
......
marker.addEventListener('click',function(){
//layer弹窗
layer.open({
content: ['http://localhost:8085/scene?sId='+data[index].sId+'','no']
});
});
}
}
})
正确的写法:
$.ajax({
...
success:function(data){
for(var index in data){
//循环创建marker
......
(function(i){
marker.addEventListener('click',function(){
//layer弹窗
layer.open({
content: ['http://localhost:8085/scene?sId='+i.sId+'','no']
});
});
})(index);
}
}
})
下面来说说闭包
1.什么是闭包?
闭包就是一个函数,这个函数能访问其它函数的作用域。
function test(){
var a = 1;
var test1 = function(){
console.log(a); //1 test1就是闭包函数,因为它能访问到test中的a
}
return test1;
}
test();
2.为啥它能访问到其它函数的作用域呢
从底层堆栈角度看的话,栈中存放基本变量类型和引用的对象类型变量的地址,堆中存放对象类型的变量,所以test执行顺序:
栈是先进后出表,当执行test的时候,内存会根据引用地址push进test的执行环境,当执行test1的时候,内存会push进test1的执行环境,这个时候,test1想console.log(a),内存就会从test1()的执行环境一级一级往下找,所以test执行环境中a对于test1来说是能获取到的,这也正是为什么闭包函数能获取到外部函数的作用域的原理。
3.需要注意的地方:引用的变量可能发生变化(就是我上边遇到的那种问题)
例子:
function createFunctions() {
var result = new Array();
for(var i=0; i<10; i++) {
result[i] = function() {
console.log(i);
}
}
return result;
}
var result = createFunctions();
for(var i = 0;i< 10;i++){
result[i](); //这个时候控制台打印的是10个9 而不是0 1 2 3 4 5...
}
//调用result[i]()时工作过程
result[0] = function() { console.log(i);};
result[1] = function() { console.log(i); };
result[2] = function() { console.log(i); };
原因: 根据2的栈中的示意图,createFunctions()先执行,当执行完的时候会去result[i]的运行环境中找i,而此时i已经循环完毕变为9,所以result[i]每次打印出来的都是9.(声明一个函数的时候引擎不会对其中的变量进行赋值操作,调用的时候才去顺着运行链去找值)
正确写法:
function createFunctions() {
var result = new Array();
for(var i=0; i<10; i++) {
result[i] = (function(num) {
return function(){
console.log(i);
}
})(i);
}
return result;
}
var result = createFunctions();
for(var i = 0;i< 10;i++){
result[i](); //这个时候控制台打印的是0 1 2 3 4 5...
}