2013-04-03 51 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

字符串(和其它原始類型 通過值傳遞,陣列(和其他非原始類型通過參考更具體:變量參考對象被按值傳遞(當通過的新變種持有引用的副本)

所以你返回什麼是你的字符串的「複製」