2010-10-25 15 views
3

我正在嘗試在JavaScript中創建一個類。我用JSON類型的對象來創建它。Javascript類+屬性不符合它們的值

這樣做:

Foo = { 
    PubId: '', 

    Init:function(oCallback) 
    { 
     this.sendCommand('INIT', {}, oCallback); 
    }, 

    sendCommand : function(sCommand, aParams, oCallback) 
    { 

     setTimeout(oCallback, 1000, '{"response":"INIT","time":1287982024,"pubid":"4cc50bc47c7b3"}'); 

     return true; 
    }, 
    onData : function(sData) 
    { 
     var aRes = JSON.parse(sData); 

     this.PubId = aRes.pubid; 
     alert(this.PubId); 
     return this.PubId; 
    }, 
    umtest:function(){ alert(this.PubId); } 
} 

然後我也這樣做,包括劇本後:

Foo.Init(Foo.onData); 

的問題是,this.PubId是昂達方法內部更新,但它的外,pubid是空的。

我很新的JavaScript類,所以我不知道需要做什麼,所以我希望有人可以幫助我。 :)

感謝您的時間!

回答

2

那麼你在這裏有兩個問題。 第一個問題不瞭解如何在Javascript中使用this。當Foo.onData通過setTimeout(oCallback, ...)調用時,this將引用全局對象而不是Foo

爲了與Foo稱呼它爲this你應該改變你的代碼:

sendCommand: function (sCommand, aParams, oCallback) { 
    var that = this;   // save this reference 
    setTimeout(function() { 
     oCallback.call(that, // call the function with it 
       '{"response":"INIT","time":1287982024,"pubid":"4cc50bc47c7b3"}'); 
    }, 1000); 
    return true; 
}, 

爲了測試有什麼變化的地方這個代碼onData

// is `this` really Foo or the global object? 
alert(this === Foo); // should be true 
alert(this === window); // should be false 

在更新版本this將正確引用Foo作爲其調用對象。

有可能與你所面臨的第二問題是,你調用setTimeout功能只1000 ms = 1s後執行,因此,如果你只是檢查Fooalert(Foo.PubId)之外,你會得到一個空字符串(因爲不是招回調目前尚未被調用)。

爲了測試是否Foo.PubId確實改變:

// execute the check after 2s so as to 
// make sure the callback has been called 
setTimeout(function() { 
    alert(Foo.PubId); 
}, 2000); 

您可以查看完整的測試用例here

+1

感謝您的幫助!對於其他人也是如此。大聲笑的願望我可以投票給你們所有人,但我想我必須是該網站的用戶多一點,然後才能做到這一點。無論如何,感謝解決galambalazs。我不知道JavaScript通過函數而不是方法。瘸!任何人,與代碼。 (那個jsbin網站也很酷!) – dab 2010-10-25 22:01:53

+0

玩得開心! :) – galambalazs 2010-10-26 13:29:03

0

onData與班級分開執行。

你有這樣

Foo.Init(function(d) { Foo.onData(d);}); 

如excpected這個工作調用。

+0

這是一個*匿名函數*,而不是*閉包*。 – galambalazs 2010-10-25 13:51:22

0

這是一個範圍問題。當您將Foo.onData傳遞給您的init函數時,它會「失去」與課程的連接。函數是第一類對象,所以它們可以自己存在。你可以做到以下幾點:

Foo = { 
    PubId: '', 

    Init:function(oCallback, scope) 
    { 
     this.sendCommand('INIT', {}, oCallback, scope); 
    }, 

    sendCommand : function(sCommand, aParams, oCallback, scope) 
    { 
     var cb = oCallback; 
     if(scope) { 
      cb = function(data) { 
       oCallback.call(scope, data); 
      }; 
     } 

     setTimeout(cb, 1000, '{"response":"INIT","time":1287982024,"pubid":"4cc50bc47c7b3"}'); 

     return true; 
    } 
    //... 
} 

,然後把它與

Foo.Init(Foo.onData, Foo); 

傳遞給call()將成爲this方法中的第一個參數。

+0

啊哈,謝謝你的建議! :D – dab 2010-10-25 22:02:58

1

當屬於一個對象的方法使用點符號調用,它的上下文(其中this指向)是它的連接到所述對象。例如:

// Context: `this` is `myObj` 
myObj.myMethod(); 

但是,當存儲在一個不同的變量,以該函數的引用,它失去該上下文關係和上下文成爲全局對象:

// Context: `this` is the global object - `window` in a web browser 
var myMethod = myObj.myMethod; 
myMethod(); 

當執行方法,你可以用它callapply方法來指定上下文,你想它在執行:

// Context: `this` is `myObj` 
var myMethod = myObj.myMethod; 
myMethod.call(myObj); 

在你的具體的例子,我會考慮使用在名爲bind的新版JavaScript中引入的新方法。 bind由IE9,Firefox 4和更新版本的Google Chrome和Safari支持,它允許您將功能「鎖定」到特定的上下文。您可以實現大部分功能在不使用下面的代碼(從MDC文件採取Function.prototype.bind)支持的瀏覽器:

// PARTIAL WORKAROUND for Function.prototype.bind 
if (!Function.prototype.bind) 
    Function.prototype.bind = function(context /*, arg1, arg2... */) { 
     'use strict'; 
     if (typeof this !== 'function') throw new TypeError(); 
     var _slice = Array.prototype.slice, 
      _concat = Array.prototype.concat, 
      _arguments = _slice.call(arguments, 1), 
      _this = this, 
      _function = function() { 
       return _this.apply(this instanceof _dummy ? this : context, 
        _concat.call(_arguments, _slice.call(arguments, 0))); 
      }, 
      _dummy = function() {}; 
     _dummy.prototype = _this.prototype; 
     _function.prototype = new _dummy(); 
     return _function; 
}; 

在代碼中使用它很簡單:

Foo.Init(Foo.onData.bind(Foo)); 
+0

感謝您的建議!我寧願不依賴於解決方法,而是讓它適用於舊瀏覽器。 :/ – dab 2010-10-25 22:02:33

+0

@dab:這不是一個真正的「解決方法」,它只是一個功能較少的實現。這裏沒有要求缺少的功能。對於你需要做的事情,* bind()*會是更好的解決方案,因爲你非常地控制了從參考點(你調用Init方法的地方)的上下文。對於較新的瀏覽器,結果會更快,因爲有一個本地解決方案。 – 2010-10-26 09:27:39

相關問題