Javascript变量范围问题

时间:2011-08-22 04:21:47

标签: javascript

我正在为地图创建一个标记列表,当它们被拖动到地图上时(通过jquery draggable) - 图像将替换为地图标记。

我遇到的问题是,在创建标记控制器时 - 它们每个都有一个特定类型 - 从列表中提取。当我遍历列表时,每个可拖动元素都会被赋予其'stop'函数,该函数使用变量'type'...现在当每个元素被拖动时 - 它们都表现为它们是最后一个的'类型'元素,而不是他们自己的。

有人可以建议我如何重组这个,以便每个标记保持其特定类型吗?

var createMarkerControl = function(){       
   var markerTypes = ['custom', 'exit', 'food', 'medical', 'shelter', 'video'];
   var control = document.createElement('div');
   control.setAttribute('id', 'markerInput');

    for (var i = 0; i < markerTypes.length; i++){
       var image = document.createElement('img');
       image.setAttribute('id', 'draggable-' + markerTypes[i]);
       image.setAttribute('src', 'images/gui/' + markerTypes[i] + '.png');
       image.style.width = '30px';

       //Set type
       var type = markerTypes[i];

       //Make elements dragable/dropable                
       control.appendChild(image);

       $(image).draggable({
          helper: 'clone',
          stop: function(e){
             //Add marker to map
             var point = new google.maps.Point(e.pageX, e.pageY);
             customMap.addPlacemark(point, type);
          },
          cursorAt: {left: 15, top: 0}
       });


    }

    map.controls[google.maps.ControlPosition.RIGHT_CENTER].push(control);
}

4 个答案:

答案 0 :(得分:3)

这是因为JavaScript没有块级范围,只有功能级范围。 imagetype变量的范围限定为createMarkerControl,而不是循环。更重要的是,它们的范围是之外的可拖动闭包,因此每个闭包都将共享type变量。

我认为你希望你的内循环看起来更像这样:

var createMarkerControl = function(){       
   var markerTypes = ['custom', 'exit', 'food', 'medical', 'shelter', 'video'];
   var control = document.createElement('div');
   control.setAttribute('id', 'markerInput');

   var createDraggable = function(image, type) {
       image.setAttribute('id', 'draggable-' + type);
       image.setAttribute('src', 'images/gui/' + type + '.png');
       image.style.width = '30px';

       //Make elements dragable/dropable                
       control.appendChild(image);

       $(image).draggable({
          helper: 'clone',
          stop: function(e){
             //Add marker to map
             var point = new google.maps.Point(e.pageX, e.pageY);
             customMap.addPlacemark(point, type);
          },
          cursorAt: {left: 15, top: 0}
       });
   };

    for (var i = 0; i < markerTypes.length; i++){
       var image = document.createElement('img');

       //Set type
       var type = markerTypes[i];

       createDraggable(image, type);

    }

    map.controls[google.maps.ControlPosition.RIGHT_CENTER].push(control);
}

通过将逻辑放在子函数中,可以确保对typeimage的引用对于内部闭包是唯一的。

答案 1 :(得分:2)

我不认为JavaScript中的for循环会获得自己的变量范围(就像它们有时会在其他语言中一样),因此您定义的type变量绑定在函数的范围内。所以你真的需要另一个坚实的范围。

我个人会为您生成一个帮助函数,为您生成stop个闭包。这将创建一个稳定的范围,你的关闭可以生活...像这样:

var createMarkerControl = function(){       
   var markerTypes = ['custom', 'exit', 'food', 'medical', 'shelter', 'video'];
   var control = document.createElement('div');
   control.setAttribute('id', 'markerInput');

    for (var i = 0; i < markerTypes.length; i++){
       var image = document.createElement('img');
       image.setAttribute('id', 'draggable-' + markerTypes[i]);
       image.setAttribute('src', 'images/gui/' + markerTypes[i] + '.png');
       image.style.width = '30px';

       //Set type
       var type = markerTypes[i];

       //Make elements dragable/dropable                
       control.appendChild(image);

       $(image).draggable({
          helper: 'clone',
          stop: createStopper(type),
          cursorAt: {left: 15, top: 0}
       });


    }

    map.controls[google.maps.ControlPosition.RIGHT_CENTER].push(control);
}


var createStopper = function(type) {
    return function(e){
        var point = new google.maps.Point(e.pageX, e.pageY);
        customMap.addPlacemark(point, type);
    }   
} 

答案 2 :(得分:0)

试试这个:

   $(image).data('type',type).draggable({
      helper: 'clone',
      stop: function(e){
         //Add marker to map
         var point = new google.maps.Point(e.pageX, e.pageY);
         customMap.addPlacemark(point, $(this).data('type'));
      },
      cursorAt: {left: 15, top: 0}
   });

在您的代码中,type循环中每次迭代都会覆盖for,但在任何给定的迭代中type的值永远不会附加到可拖动的图像上,而是简单地在stop回调中引用。在stop被触发时,type值就在它的最后一次分配上。我在上面提供的想法是简单地将type的值附加到对象,以便它可以在回调中从内部引用它。

答案 3 :(得分:0)

我知道正确的答案已经发布并且它们很好但是一个简单的(IMHO)解决方案只是在(function(){ ... })();中包装您需要的代码,以便创建一个新的范围。

var createMarkerControl = function(){       
    var markerTypes = ['custom', 'exit', 'food', 'medical', 'shelter', 'video'];
    var control = document.createElement('div');
    control.setAttribute('id', 'markerInput');

    for (var i = 0; i < markerTypes.length; i++)
    (function() {
       var image = document.createElement('img');
       image.setAttribute('id', 'draggable-' + markerTypes[i]);
       image.setAttribute('src', 'images/gui/' + markerTypes[i] + '.png');
       image.style.width = '30px';

       //Set type
       var type = markerTypes[i];

       //Make elements dragable/dropable                
       control.appendChild(image);

       $(image).draggable({
          helper: 'clone',
          stop: function(e){
             //Add marker to map
             var point = new google.maps.Point(e.pageX, e.pageY);
             customMap.addPlacemark(point, type);
          },
          cursorAt: {left: 15, top: 0}
       });


    })();

    map.controls[google.maps.ControlPosition.RIGHT_CENTER].push(control);
}

http://jsfiddle.net/xXkcG/2/