我认为这个问题超出了典型的变量范围和闭包的范围,或者我是个白痴。无论如何...

我正在使用jQuery插件动态创建一堆对象。对象看起来像这样

function WedgePath(canvas){
    this.targetCanvas = canvas;
    this.label;
    this.logLabel = function(){ console.log(this.label) }
}

jQuery插件看起来像这样
(function($) {
  $.fn.myPlugin = function() {

  return $(this).each(function() {

     // Create Wedge Objects
     for(var i = 1; i <= 30; i++){
      var newWedge = new WedgePath(canvas);
      newWedge.label = "my_wedge_"+i;
      globalFunction(i, newWedge]);
     }
    });
  }
})(jQuery);

所以...该插件创建了一堆楔子对象,然后为每个对象调用'globalFunction',并传入最新的WedgePath实例。全局函数如下所示。
function globalFunction(indicator_id, pWedge){

    var targetWedge = pWedge;
    targetWedge.logLabel();

}

接下来,控制台将正确记录每个楔形标签。但是,我需要在globalFunction内部增加一些复杂性。所以实际上看起来像这样...
function globalFunction(indicator_id, pWedge){

        var targetWedge = pWedge;

        someSql = "SELECT * FROM myTable WHERE id = ?";
        dbInterface.executeSql(someSql, [indicator_id], function(transaction, result){

            targetWedge.logLabel();

        })

    }

这里发生了很多事情,所以我会解释。我正在使用客户端数据库存储(我称之为WebSQL)。 “dbInterface”是我创建的简单javascript对象的实例,该对象处理与客户端数据库交互的基础知识(在本问题的末尾显示)。 executeSql方法最多包含4个参数
  • SQL字符串
  • 可选参数数组
  • 可选的onSuccess处理程序
  • 可选的onError处理程序(在此示例中未使用)

  • 我需要做的是:WebSQL查询完成后,它将获取其中一些数据并操纵特定楔形的某些属性。但是,当我在onSuccess处理程序内的WedgePath实例上调用“logLabel”时,我得到了WedgePath的最后一个实例的标签,该标签是在插件代码中创建的。

    现在我怀疑问题出在var newWedge = new WedgePath(canvas);线。所以我尝试将每个newWedge推入一个数组,我认为这可以防止该行在每次迭代时替换或覆盖WedgePath实例。
    wedgeArray = [];
    
    // Inside the plugin...
    for(var i = 1; i <= 30; i++){
        var newWedge = new WedgePath(canvas);
        newWedge.label = "my_wedge_"+i;
        wedgeArray.push(newWedge);
    }
    
    for(var i = 0; i < wedgeArray.length; i++){
        wedgeArray[i].logLabel()
    }
    

    但同样,我得到了要创建的WedgePath的最后一个实例。

    这让我发疯。对于问题的长度,我深表歉意,但我想尽可能清楚。

    结束

    ================================================== ============

    此外,以下是dbInterface对象的代码:
    function DatabaseInterface(db){
    
     var DB = db;
    
     this.sql = function(sql, arr, pSuccessHandler, pErrorHandler){
    
      successHandler = (pSuccessHandler) ? pSuccessHandler : this.defaultSuccessHandler;
      errorHandler = (pErrorHandler) ? pErrorHandler : this.defaultErrorHandler;
    
      DB.transaction(function(tx){
    
       if(!arr || arr.length == 0){
        tx.executeSql(sql, [], successHandler, errorHandler);
       }else{
        tx.executeSql(sql,arr, successHandler, errorHandler)
       }
    
      });
     }
    
     // ----------------------------------------------------------------
     // A Default Error Handler
     // ----------------------------------------------------------------
    
     this.defaultErrorHandler = function(transaction, error){
      // error.message is a human-readable string.
         // error.code is a numeric error code
         console.log('WebSQL Error: '+error.message+' (Code '+error.code+')');
    
         // Handle errors here
         var we_think_this_error_is_fatal = true;
         if (we_think_this_error_is_fatal) return true;
         return false;
     }
    
    
     // ----------------------------------------------------------------
     // A Default Success Handler
     // This doesn't do anything except log a success message
     // ----------------------------------------------------------------
    
     this.defaultSuccessHandler = function(transaction, results)
      {
          console.log("WebSQL Success. Default success handler. No action taken.");
      }
    }
    

    最佳答案

    我猜这是由于客户端数据库存储像AJAX调用那样异步运行。这意味着它不会为了等待被调用方法的结果而停止调用链。

    结果,javascript引擎在运行globalFunction之前完成了for循环。

    要解决此问题,您可以在闭包内执行db查询。

    function getDataForIndicatorAndRegion(indicator_id, region_id, pWedge){
        return function (targetWedge) {
            someSql = "SELECT dataRows.status FROM dataRows WHERE indicator_id = ? AND region_id = ?";
            dbInterface.sql(someSql, [indicator_id, region_id], function(transaction, result) {
                targetWedge.changeColor(randomHex());
            });
        }(pWedge);
    }
    

    这样,您可以为每次执行保留pWedge。由于第二种方法是自我调用它并发送pWedge现在作为参数。

    编辑:从注释更新了代码。并进行了更改。回调函数也许不应该被自我调用。如果调用自身,则函数的结果将作为参数传递。另外,如果它不起作用,请尝试传递其他参数。

    07-24 16:50