【问题标题】:Implementing instance members/methods in JavaScript在 JavaScript 中实现实例成员/方法
【发布时间】:2013-05-17 07:32:27
【问题描述】:

这个问题源于我试图解决的一个问题,即在 JavaScript 中拥有“私有”实例变量的能力。在我提出问题之前,您可能想阅读this

为了完整起见,在提出问题之前,我已经说明了我的整个问题。我希望这将提供一个完整的示例,说明如何在 JavaScript 中正确实现实例成员和方法,并让任何来到这里的开发人员了解各种实现的陷阱。

考虑以下 JavaScript 对象:

var MessageBox = (function() {
    function MessageBox(message) {
        this.message = message;
    }

    MessageBox.prototype.Show = function() {
        alert(this.message);
    }
})();

这个对象是用 TypeScript 建模的,可以按如下方式使用:

var msg1 = new MessageBox("Hello World");
msg1.Show(); // alerts "Hello World"

var msg2 = new MessageBox("Bye World");
msg2.Show(); // alerts "Bye World"

但我仍然可以调用:

msg1.message; // "Hello World"
msg2.message; // "Bye World"

很明显this.message 不是私人的。

现在考虑以下 JavaScript 对象:

var MessageBox = (function() {
    return function MessageBox(message) {
        var message = message;

        MessageBox.prototype.Show = function() {
            alert(message);
        }
    }
})();

这只是基于 TypeScript 的 MessageBox 对象的修改版本。

var msg1 = new MessageBox("Hello World");
msg1.Show(); // alerts "Hello World"

var msg2 = new MessageBox("Bye World");
msg2.Show(); // alerts "Bye World"

但是等一下……我要扔扳手了!

var msg1 = new MessageBox("Hello World");
var msg2 = new MessageBox("Bye World");
msg2.Show(); // alerts "Bye World"
msg1.Show(); // alerts "Bye World" ... wait, what!?

msg1.message // undefined
msg2.message // undefined

所以我无法再访问消息变量,但现在,每个新实例都会覆盖最后一个实例消息。

请耐心等待,这是要考虑的最后一个 JavaScript 对象:

var MessageBox = (function() {
    return function MessageBox(message) {
        var message = message;

        this.Show = function() {
            alert(message);
        }
    }
}();

上面的对象不再在原型上实现 Show(),所以现在我可以:

var msg1 = new MessageBox("Hello World");
var msg2 = new MessageBox("Bye World");
msg2.Show(); // alerts "Bye World"
msg1.Show(); // alerts "Hello World"

msg1.message // undefined
msg2.message // undefined

太棒了!现在我有了私有变量,它们不会互相覆盖!

所以,最后的问题是:有什么区别:

MessageBox.prototype.Show = function() {
}

this.Show = function() {
}

【问题讨论】:

    标签: javascript variables prototype instance private


    【解决方案1】:

    使用MessageBox.prototype.Show,每次调用new MessageBox() 时,您都会为任何实例覆盖Show 函数。因此,每个实例总是在相同的范围内共享相同的Show 函数。

    【讨论】:

      【解决方案2】:

      你最终得到的问题有一个简单的答案:在原型上设置函数意味着它可以从任何实例中调用,而在实例上设置函数意味着它只能从该实例中调用。无论哪种方式都可以访问实例上的属性,但您发现复杂的是 无论哪种方式,函数都只能访问声明它的范围内或包含范围内的局部变量。

      下面是想到的提供私有实例和私有原型变量的第一种方式。

      var MessageBox = (function() {
          var privateProtoVar = "Hello";
      
          function MessageBox(message) {
              var privateInstanceVar = message;
      
              this.instanceMethod = function() {
                  alert(privateInstanceVar); // Can access private instance var
                  alert(privateProtoVar);    // Can access private prototype var
              }
          }        
          MessageBox.prototype.Show = function() {
              alert(privateProtoVar); // Can access private proto var
              // but can't access privateInstanceVar
          }    
          return MessageBox;
      })();
      
      var msg1 = new MessageBox("1"),
          msg2 = new MessageBox("2");
      
      msg1.instanceMethod();  // "1", "Hello"
      msg2.instanceMethod();  // "2", "Hello"
      msg1.Show();            // "Hello"
      msg2.Show();            // "Hello"
      

      变量privateInstanceVar 可以被声明在内部MessageBox() 函数 的任何函数访问,但不能从prototype 上的函数访问,除非它们是在同一范围内声明的(我不要在上面的例子中这样做)。

      如果您稍后向实例添加其他方法,即在上述结构之外,那么这些方法不能访问私有变量,因为它们是在不同的范围:

      msg1.newMethod = function() {
         alert(privateInstanceVar);
      }
      msg1.newMethod(); // error
      

      演示:http://jsfiddle.net/SSEga/

      【讨论】:

        猜你喜欢
        • 2013-11-21
        • 1970-01-01
        • 2018-10-12
        • 1970-01-01
        • 2012-03-14
        • 2019-01-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多