代码之家  ›  专栏  ›  技术社区  ›  Manuel Bitto

javascript“class”和singleton问题

  •  9
  • Manuel Bitto  · 技术社区  · 16 年前

    我有一个singleton对象,它使用另一个对象(而不是singleton)来要求服务器提供一些信息:

    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
      }
    

    }

    问题是我不能从singleton对象内部调用myRequestManager.require。Firebug控制台说:“myRequestManager.require不是一个函数”,但我不知道问题在哪里。 有没有更好的解决方案来实施这种情况?

    1 回复  |  直到 11 年前
        1
  •  6
  •   T.J. Crowder    16 年前

    你的代码是按照你引用的顺序排列的,是吗?单子出现在 RequestManager 在源头?

    如果是这样,那就是你的问题。这是相当微妙的!!),但假设您的两位引用代码是按照您显示的顺序排列的,下面是事情发生的顺序(我将在下面详细解释):

    1. 函数 请求管理器 定义。
    2. 创建单例运行的匿名函数,包括实例化 请求管理器 .
    3. 这个 请求管理器 原型被一个新的替换了。

    自从 myRequestManager 实例已实例化 之前 原型已更改,它没有您在该(新)原型上定义的函数。它继续使用在实例化时已就位的原型对象。

    您可以通过重新排序代码或将属性添加到 请求管理器 而不是替换它的原型,例如:

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

    因为你没有 替换 原型对象,您刚刚添加到其中。 我的请求经理 查看添加项,因为您已将它们添加到它使用的对象中(而不是在构造函数的 prototype 财产)。

    发生这种情况的原因有点技术性,我将主要遵从规范。当解释器进入一个新的“执行上下文”(例如,函数或全局-例如,页级-上下文)时,它执行事情的顺序不是严格的自上而下的源顺序,而是有阶段的。第一个阶段之一是实例化上下文中定义的所有函数;这会发生 之前 执行任何分步代码。在第10.4.1节(全球代码)、第10.4.3节(功能代码)和第10.5节(声明绑定)中详细介绍了它们的辉煌。 the spec 但基本上,函数是在第一行逐步代码之前创建的。-)

    用一个单独的测试示例最容易看到这一点:

    <!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 它使用*的实例(因为原型被扩充,而不是被替换)。