Javascript 闭包:如何将动态底层添加到 Cesium 地图

Javascript closure: How to add dynamic baselayers to Cesium map

我正在尝试从数据库中的一组值向 Cesium 地图添加多个基础层。我希望 javascript 只是遍历它们然后添加它们。这是来自 Cesium 的静态代码示例:

var imageryViewModels = [];
imageryViewModels.push(new Cesium.ProviderViewModel({
     name : 'Open\u00adStreet\u00adMap',
     iconUrl : Cesium.buildModuleUrl('openStreetMap.png'),
     tooltip : 'OpenStreetMap (OSM)',
     creationFunction : function() {
         return Cesium.createOpenStreetMapImageryProvider({
             url : 'https://a.tile.openstreetmap.org/'
         });
     }
 }));

 imageryViewModels.push(new Cesium.ProviderViewModel({
     name : 'Black Marble',
     iconUrl : Cesium.buildModuleUrl('blackMarble.png'),
     tooltip : 'outlines of civilization',
     creationFunction : function() {
         return Cesium.createTileMapServiceImageryProvider({
             url : 'https://cesiumjs.org/blackmarble',
             credit : 'B Observatory',
             flipXY : true
         });
     }
 }));

到目前为止,使用一组静态值非常简单。这就是它变得棘手的地方,我想遍历一组值,然后将 ProviderViewModels 推送到数组。像这样 -

var imageryViewModels = [];
baseLayers = HashOfValuesFromDatabase;
for(int i=0; i<baseLayers.length; i++{

  imageryViewModels.push(new Cesium.ProviderViewModel({
       name : baseLayers[i].name,
       iconUrl : Cesium.buildModuleUrl(baseLayers[i].iconUrl),
       tooltip : baseLayser[i].toolTip,
       creationFunction : function() {
           return Cesium.createOpenStreetMapImageryProvider({
               url : baseLayers[i].url   // ***** this value always the last value ****
           });
       }
   }));

}

问题是 javascript 闭包给我带来了问题,我的每一个 imageryViewModels 都是 baseLayer.url 对象中的最后一个值。 Cesium 需要 this 在这里成为一个函数。有没有办法让这个函数保持不变,但得到迭代的值 baseLayer.url?

请试试这个(我没有运行):

var imageryViewModels = [];
baseLayers = HashOfValuesFromDatabase;
for(int i=0; i<baseLayers.length; i++{

  imageryViewModels.push(new Cesium.ProviderViewModel({
       name : baseLayers[i].name,
       iconUrl : Cesium.buildModuleUrl(baseLayers[i].iconUrl),
       tooltip : baseLayser[i].toolTip,
       creationFunction : (function(i) {
           return function() {
             return Cesium.createOpenStreetMapImageryProvider({
                 url : baseLayers[i].url  
             });
           }
       }(i))
   }));

}

编辑:语法正确(感谢 emackey)

Ben Aston 的回答是这里的正确方法。他没有尝试 运行ning 它,并且在 }(i)) 之后有一个额外的分号在参数列表中是非法的,而且他还从您的原始问题中复制粘贴了一些问题。这是更正后的版本,我确实得到了 运行:

var imageryViewModels = [];
for(var i=0; i<baseLayers.length; i++) {

  imageryViewModels.push(new Cesium.ProviderViewModel({
       name : baseLayers[i].name,
       iconUrl : Cesium.buildModuleUrl(baseLayers[i].iconUrl),
       tooltip : baseLayers[i].toolTip,
       creationFunction : (function(i) {
           return function() {
             return Cesium.createOpenStreetMapImageryProvider({
                 url : baseLayers[i].url  
             });
           };
       }(i))
   }));
}

修复 url 参数的原因是因为 IIFE(立即调用的函数表达式)使用 i 作为参数。这会在循环中的每次迭代中创建一个新的 JavaScript 闭包,这很昂贵,但这是必需的,以便每个单独的 create 函数都有自己的闭包,并具有自己的 [=13= 值副本] 来自循环的特定迭代。没有这个,只有一个闭包只有一个 i 变量,并且当任何一个创建函数被实际调用时,循环早就完成了并且 i 的值已经达到最大值.