簡體   English   中英

JavaScript'類'和單例問題

[英]JavaScript 'class' and singleton problems

我有一個單例對象使用另一個對象(而不是單例),要求服務器的一些信息:

var singleton = (function(){

  /*_private properties*/
  var myRequestManager = new RequestManager(params,
    //callbacks
    function(){
        previewRender(response);
    },
    function(){
        previewError();
    }
  );

  /*_public methods*/
  return{

    /*make a request*/
    previewRequest: function(request){
       myRequestManager.require(request);  //err:myRequestManager.require is not a func
    },

    previewRender: function(response){
      //do something
    },

    previewError: function(){
      //manage error
    }
  };
}());

這是向服務器發出請求的“類”

function RequestManager(params, success, error){
  //create an ajax manager
  this.param = params;
  this._success = success;  //callbacks
  this._error = error;
}

RequestManager.prototype = {

  require: function(text){
    //make an ajax request
  },
  otherFunc: function(){
     //do other things
  }

}

問題是我無法從單例對象中調用myRequestManager.require。 Firebug consolle說:“myRequestManager.require不是函數”,但我不明白問題出在哪里。 有沒有更好的解決方案來實現這種情況?

你的代碼按你引用的順序排列,不是嗎? 單例顯示在源中的RequestManager上方?

如果是這樣,那就是你的問題。 這是相當微妙的(!),但假設您的兩位引用代碼按照您顯示的順序排列,這里是事情發生的順序(我將在下面詳細解釋):

  1. 函數RequestManager已定義。
  2. 創建單例運行的匿名函數,包括實例化RequestManager實例。
  3. RequestManager原型被替換為新原型。

由於myRequestManager實例在原型更改之前已實例化,因此它沒有您在該(新)原型上定義的函數。 它繼續使用實例化時原型對象。

您可以通過重新排序代碼或通過向RequestManager的原型添加屬性而不是替換它來輕松解決此問題,例如:

RequestManager.prototype.require = function(text){
    //make an ajax request
};
RequestManager.prototype.otherFunc = function(){
    //do other things
};

這是有效的,因為你沒有替換原型對象,你剛剛添加它。 myRequestManager看到了添加內容,因為您已將它們添加到它正在使用的對象中(而不是在構造函數的prototype屬性上設置新對象)。

為什么會發生這種情況有點技術性,我將主要遵循規范。 當解釋器輸入新的“執行上下文”(例如,函數或全局 - 例如,頁面級 - 上下文)時,它執行操作的順序不是嚴格的自上而下的源順序,而是存在階段。 第一階段之一是實例化上下文中定義的所有函數; 在執行任何分步代碼之前發生的事情。 詳見10.4.1(全局代碼),10.4.3(功能代碼)和10.5(聲明綁定)中所有榮耀,但基本上,這些函數是在第一行逐步代碼之前創建的。 :-)

使用隔離的測試示例最容易看到:

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<title>Test Page</title>
<style type='text/css'>
body {
    font-family: sans-serif;
}
</style>
<script type='text/javascript'>
// Uses Thing1
var User1 = (function() {
    var thing1 = new Thing1();

    function useIt() {
        alert(thing1.foo());
    }

    return useIt;
})();

// Uses Thing2
var User2 = (function() {
    var thing2 = new Thing2();

    function useIt() {
        alert(thing2.foo());
    }

    return useIt;
})();

// Thing1 gets its prototype *replaced*
function Thing1() {
    this.name = "Thing1";
}
Thing1.prototype = {
    foo: function() {
        return this.name;
    }
};

// Thing2 gets its prototype *augmented*
function Thing2() {
    this.name = "Thing2";
}
Thing2.prototype.foo = function() {
    return this.name;
};

// Set up to use them
window.onload = function() {
    document.getElementById('btnGo').onclick = go;
}

// Test!
function go() {

    alert("About to use User1");
    try
    {
        User1();
    }
    catch (e)
    {
        alert("Error with User1: " + (e.message ? e.message : String(e)));
    }

    alert("About to use User2");
    try
    {
        User2();
    }
    catch (e)
    {
        alert("Error with User2: " + (e.message ? e.message : String(e)));
    }
}

</script>
</head>
<body><div>
<div id='log'></div>
<input type='button' id='btnGo' value='Go'>
</div></body>
</html>

正如您所看到的,如果您運行它, User1失敗,因為它正在使用的Thing1實例沒有foo屬性(因為原型已被替換),但User2可以工作,因為它使用的Thing2實例* Thing2 (因為原型是增強的,沒有替換)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM