循环覆盖数据的内部值

时间:2017-03-08 21:26:41

标签: javascript closures leaflet

每次运行此循环时,markers数组中的每个标记都会被let icon = iconLoader.getIcon(data[index][5]);的结果覆盖。 保留每个标记具有最后加载的图标,而不是在for循环的每次传递期间加载图标。

我认为将图标传递到闭包中实际上会按值传递它,防止它被覆盖在闭包范围之外,但这对我来说似乎并不适用。我错过了什么?

var markers = []   
for (var index in data) {    
    let icon = iconLoader.getIcon(data[index][5]);
    var createMarker = (function (i) {  
        return function () {
            var marker = new L.marker([data[index][2], data[index][3]])
                .setIcon(i)    
            markers.push(marker);
        }
    })(icon);
    createMarker();
}

var iconLoader = (function () {   
    var icon = L.icon({
        // options
    });    
    return {
        getIcon: function (iconName) {
            // do stuff to get icon
            return icon;
        }
    };
}());

JSFiddle

2 个答案:

答案 0 :(得分:1)

因此,正如我在原始评论中提到的,除非您明确创建并传递副本,否则JavaScript对象和数组始终通过引用传递。您的代码中没有任何内容本身就是错误的并且不会导致此问题 - 实际上这是leaflet如何在内部处理对象引用的问题。避免这种情况的方法是对iconLoader.getIcon()的结果执行深层复制。如果您使用的是jQuery,则可以使用$.extend()非常简单地完成。

for (var index in data) {
  let icon = $.extend(true, {}, iconLoader.getIcon(data[index][2]));
  var marker = new L.marker([data[index][0], data[index][1]])
  .setIcon(icon);     
  markers.push(marker);
}

如果没有,你可以查看非jQuery解决方案 - 它并不理想,但它们无处不在。

答案 1 :(得分:0)

我正在打字,因为mhodges在写他的答案。我会继续发布它,因为它是一个不同的解决方案,也为我解决了这个问题。

看着mhodges'工作演示,我注意到他设置的iconloader有点不同于我。他把iconloader作为对象......

var iconLoader = {
    getIcon: function (elem) {
        return elem;
    }
 }

而我的设立是封闭......

var iconLoader = (function () {   
    var icon = L.icon({
        // options
    });    
    return {
        getIcon: function (iconName) {
            // do stuff to get icon
            return icon;
        }
    };
}());

我想也许我可以试着设置一下,看看是否有所不同,还有VOILA!

const proto = {
        getIcon (iconName) {
            var icon = L.icon({
                // options
            });   
            // do stuff to get icon
            return icon;
        }
    };

function factoryIcon() {
    return Object.create(proto);
}

然后用

抓住图标
const iconFactory = factoryIcon();
let icon = iconFactory.getIcon(data[index][5]);