2013-04-03 29 views
0

下面是一个代码大大简化片断从SlickGrid样品衍生自:很困惑有关JavaScript作用域

model.js:

(function($) { 
    function RemoteModel() { 
     var someArr=[0]; 
     var someVar=0; 
     var onDataLoadedSuccess = new Slick.Event(); 

     function ensureData(from, to) { 
      h_request = setTimeout(function() { 
       req = $.ajax({ 
        url: url, 
        context: this, 
        success: function(resp) { 
         onSuccess(); 
        } 
       }); 
      }, 3000); 
     } 

     function onSuccess() { 
      someVar=someVar+100; 
      someArr[0]=someArr[0]+100; 
      console.log(someVar + " " + someArr[0]); // yes values are changing properly for both ! 

      onDataLoadedSuccess.notify({ from: from, to: to }); 
     } 

     return { 
      "someArr": someArr, 
      "someVar": someVar, 
      "onDataLoadedSuccess": onDataLoadedSuccess, 
     }; 
    } 
})(jQuery); 

main.js:

var loader=new RemoteModel(); 
var grid=new Slick.Grid("#wlGrid", loader.data, columns, options); 

grid.onViewportChanged.subscribe(function(e, args) { 
    var vp = grid.getViewport(); 
    loader.ensureData(vp.top, vp.bottom); 
}); 

loader.onDataLoadedSuccess.subscribe(function(e, args) { 
    // someVar is always 0 :(! someArr[0] is changing fine .. why ??? 
    console.log(loader.someVar + " " + loader.someArr[0]); 
}); 

因此,网格上的事件(onViewportChanged)在m上调用ensureData odel,其中 增量为someVarsomeArr[0],两者均由RemoteModel的返回值 公开。

递增活动结束后,onDataLoadedSuccess由模型中的事件只有loader.someArr[0]值已改变内然而 触发。

为什么someVar的值在onDataLoadedSuccess总是零?这是范围问题吗? 为什么someArr[0]的值改变正常?

我该如何正确读取onDataLoadedSuccesssomeVar的值?

+0

OK,我认为我明白现在发生了什么,谢谢大家! 但是,我如何使一些变量工作?我需要让构造函数返回一个对象(因为这里有很多方法),但我仍然希望允许thisVar可以从ensureData,onSuccess和onDataLoadedSuccess访问? – kofifus

回答

0

RemoteModel函数的局部变量为someVarsomeArr。当创建loader时,这些也会作为对象属性返回。不同之处在于someVar的编号值在创建时被有效复制到loader中。

该阵列也被复制到someArr中,但该副本仅供参考。因此你有两件事情指向同一个数组。当事件执行时,它会更新本地变量和本地数组。loader指向同一个数组,所以你看到someArr[0]发生了变化,但它并没有“指向”这个数字,所以当本地someArr被更改时loader的值不是。

编辑解决意见

一种选择是,先定义你返回的对象,然后让你的私有函数引用它。这可能仅限于数字或适用于所有公众成员;为了清晰起见,我会做后者。采用这种方法,只有类需要改变,而不是调用它的代码。

function RemoteModel() { 
    var ret = { 
     "someArr": [0], 
     "someVar": 0, 
     "onDataLoadedSuccess": new Slick.Event() 
    };   

    function onSuccess() { 
     ret.someVar=ret.someVar+100; 
     // ... 
    } 

    return ret; 
    // ... 

第二个选择是创建一个getSomeVar方法是在你返回的对象,这样的类之外,你做loader.getSomeVar(),而不是仅仅loader.someVar。 (你可以创建一个setSomeVar(newValue),如果它需要外部设定

function RemoteModel() { 
    var someVar=0; 
    // ... 

    function getSomeVar() { 
     return someVar; 
    } 

    return { 
     "someArr": someArr, 
     "getSomeVar": getSomeVar, 
     "onDataLoadedSuccess": onDataLoadedSuccess, 
    }; 
} 

,然后:

loader.onDataLoadedSuccess.subscribe(function(e, args) { 
    console.log(loader.getSomeVar() + " " + loader.someArr[0]); 
}); 
+0

非常感谢你! 看到我对帖子的评论,现在我明白我的问题了,你能帮助解决吗? – kofifus

+0

真棒,明白了!非常感谢 – kofifus

0

当你创建了一个模型,你回到这loader

return { 
    "someArr": someArr, 
    "someVar": someVar, 
    "onDataLoadedSuccess": onDataLoadedSuccess, 
} 

loader.someArr指向由someArr在封闭指出同一阵列。然而,someVar是一个值为0的财产,复制someVar在封闭。

当为对象(包括数组)指定变量或对象属性时,您正在引用该对象。因此,loader.someArr指向闭包中由someArr指向的相同数组。由于它们指向相同的阵列,因此可以通过someArrloader.someArr完成更改。

但是在someVar的情况下,您从someVar分配loader.someVar。由于0是一个原始值,因此该值为复制someVarloader.someVar。因此,someVarloader.someVar不指向相同的东西。修改someVar不会修改loader.someVar,反之亦然。

0

号码和其他非对象基元得到的返回值,而不是参考:

return { 
     "someArr": someArr, // <-- object 
     "someVar": someVar, // <-- number 
     "onDataLoadedSuccess": onDataLoadedSuccess, 
    }; 

someArr是一个对象(数组),它将被引用返回,但someVar只是一个简单的数字,因此你返回一个值

而是在返回一个对象的你RemoteModel你应该使用RemoteModel作为一个适当的构造函数:

this.someArr=[0]; 
    this.someVar=0; 
    this.onDataLoadedSuccess = new Slick.Event(); 

    /* move other functions into the prototype, get rid of the return */ 

如果你不熟悉使用函数作为构造看到Working with Objects on MDN

+0

非常感谢你! 看到我对帖子的评论,现在我明白我的问题了,你能帮助解决吗? – kofifus

0

这是因为javascript如何处理值。

(function($) { 
    function RemoteModel() { 
     this.someArr=[0]; 
     this.someVar=0; 
     this.onDataLoadedSuccess = new Slick.Event(); 

     var _this = this; 

     function ensureData(from, to) { 
      h_request = setTimeout(function() { 
       req = $.ajax({ 
        url: url, 
        context: this, 
        success: function(resp) { 
         onSuccess(); 
        } 
       }); 
      }, 3000); 
     } 

     function onSuccess() { 
      _this.someVar=_this.someVar+100; 
      _this.someArr[0]=_this.someArr[0]+100; 
      console.log(_this.someVar + " " + _this.someArr[0]); // yes values are changing properly for both ! 

      _this.onDataLoadedSuccess.notify({ from: from, to: to }); 
     } 
    } 
})(jQuery); 
+0

太好了,谢谢!我想我非常感谢你 – kofifus

+0

非常感谢! 看到我对帖子的评论,现在我明白我的问题了,你能帮助解决吗? – kofifus

0

那是因为此刻的你返回

{ 
     "someArr": someArr, 
     "someVar": someVar, 
     "onDataLoadedSuccess": onDataLoadedSuccess, 
}; 

someVar0

someVar包含String,一种原始类型。

someArr引用一个非原始类型Array

字符串(和其它原始类型 通过值传递,阵列(和其他非原始类型通过参考更具体:变量参考对象被按值传递(当通过的新变种持有引用的副本)

所以你返回什么是你的字符串的“复制”