1

假设这段代码 javascript 代码

(function(){

NameSpace = new function(){} //global namespace

NameSpace.Apple = function(p_color){
  var AppleInstance = this; //clarity..

  AppleInstance.color = p_color;

  return {
    /**************
    / Public method
    /**************/
    //Here, we only return an access to the Method Eat
    Eat : NameSpace.Apple.prototype.Eat
  }
}

//Will be public
NameSpace.Apple.prototype.Eat = function(){
  var AppleInstance = this; //clarity..

  console.log("I'm eating a " + AppleInstance.color + " apple !")
}

//Will be private
NameSpace.Apple.prototype.PrivateMethod = function(){
  var AppleInstance = this; //clarity..

  console.log("This is a private method");
}

})()

new NameSpace.Apple("blue").Eat();
//I'm eating a undefined apple !

如您所见,我在命名空间中有一个类,其中包含 1 个私有变量、1 个私有方法和 1 个公共方法。但是当访问我的公共方法时,这个方法无法访问该类的变量。

我知道这是因为:

return {
    /*...*/
}

但是有没有一种方法可以让我的公共原型方法访问我的私有变量(在我的原始代码中我想要一个常量..)而不用返回来访问它。

如果我在返回中返回属性,原型方法将可以访问它,但不能访问它。

谢谢。

4

2 回答 2

3

没有。这两种策略有些不相容。这就是为什么私有属性通常是公共的,但在使用原型时以下划线为前缀。

Namespace.Apple = function(p_color){
  this._color = p_color;
};

Namespace.Apple.prototype.eat = function(){
  console.log("I'm eating a " + this._color + " apple !")
};

这告诉使用此代码的 JS 开发人员他们不应该弄乱该_color属性,因为它是供内部使用的。


也就是说,你这里还有其他大问题......

Namespace.Apple = function(p_color){
  var AppleInstance = this; //clarity..

  AppleInstance.color = p_color;

  return {
    /**************
    / Public method
    /**************/
    //Here, we only return an access to the Method Eat
    Eat : NameSpace.Apple.prototype.Eat
  }
}

这不符合你的想法。当构造函数返回一个对象时,创建的实例将new被丢弃。所以你最终不会得到一个Apple. 相反,您会得到一个看起来像这样的普通对象:

{ Eat: Namespace.Apple.prototype.Eat }

那么你分配颜色的对象呢?没了。


此方法不是私有的。

//Will NOT be private
Namespace.Apple.prototype.PrivateMethod = function(){
  var AppleInstance = this; //clarity..
  console.log("This is a private method");
}

原型上的所有内容都是公开的。一切。


以及关于约定的说明。

var AppleInstance = this; //clarity..

我认为根本不清楚。 this在实例方法中用于表示this实例。任何混淆都会损害可读性。

并且请为构造函数保存大写字母变量名(Eat坏!,Apple好!,AppleInstance坏!),也为了可读性。因为调用没有new关键字的构造函数可能会产生一些奇怪的后果。


为了避免这种情况,并且仍然有私有变量和方法,您根本不使用原型。您在构造函数中将所有变量和方法设置为函数,逐个构建实例。

var Namespace = {};
Namespace.Apple = function(color){
  // color form the arguments is a local variable, bound to the methods created below
  var somePrivateVar = 'privateData!'; // private instance variable

  // public method, with access to private instance vars
  this.eat = function(){
    console.log("I'm eating a " + color + " apple!");
  };

  // public method, which calls private method
  this.doSomethingPrivate = function() {
    console.log('calling private method for you');
    privateMethod()
  }

  // private method
  var privateMethod = function(){
    console.log("This is a private method for a " + color + " apple!");
  };

  // instance is auto-returned, no return needed.
}

var apple = new Namespace.Apple('red');
apple.eat();                // I'm eating a red apple!
apple.doSomethingPrivate(); // calling private method for you
                            // This is a private method for a red apple!
apple.privateMethod()       // <exception> apple.privateMethod is undefined

关于这种方法,唯一需要注意的是,它比使用原型时要慢得多,并且使用更多内存。原型上的函数在所有实例之间共享,因此您只需要为一个方法创建和存储一个函数,每个实例都会执行该函数对象。

使用上述方法,每个实例都会创建并存储每个方法函数的新副本。每个函数都有权访问该实例构造函数的范围,允许您使用私有变量和方法。如果您只计划有几个实例,那么这种差异可能不会有太大的不同。但是,如果您计划拥有大量实例,则性能差异可能变得非常重要。

于 2013-06-20T18:41:04.590 回答
0

为了实现封装,建议您遵循以下结构:

(function(){

    NameSpace = new function(){} //global namespace

    NameSpace.Apple = function(p_color){
      var AppleInstance = this; //clarity..
      var color;

      AppleInstance.color = p_color;  

      this.Eat = function(){
        /**************
        / Public method
        /**************/
        //Here, we only return an access to the Method Eat
        alert("I'm eating a " + AppleInstance.color + " apple !")
      }
      //Will be private

      var private = function(){
          var AppleInstance = this; //clarity..

          alert("This is a private method");
        }

      function constructor(p_color){
          AppleInstance.color = p_color;
      }

      constructor(p_color)
    }
})()

new NameSpace.Apple("blue").Eat();
//I'm eating a blue apple !

new NameSpace.Apple("blue").private();
// Exception raised

我从不赞成忽略this本地副本的变量,它对 JS 对象的调用结构内的范围有重要影响,并为开发人员提供了关于这些可能发生变化的地方的线索。

顺便说一句:Namespace.Apple.prototype.PrivateMethod不会是私有方法,因为通过原型公开的所有内容都是公开的。

于 2013-06-20T18:54:14.453 回答