JavaScript类和变量范围

时间:2009-11-30 22:57:30

标签: javascript variables class

我对JS比较新,我遇到了正确模仿OOP原则的问题。

我想我有两个问题。问题首先是关于声明变量的许多方法。

说我有课:

function clazz(a)
{
    this.b = 2;
    var c = 3;
    this.prototype.d = 4; // or clazz.prototype.d = 4?
}

var myClazz = new clazz(1); 

我在以下评估中是否正确:

a是一个特定于实例的私有变量(即clazz的不同实例将具有唯一且独立的变量'a')。它可以从clazz中访问:'a'。

b是一个特定于实例的公共变量。它可以在clazz中作为'this.b'访问,也可以从外部clazz访问'myClazz.b'。

c是一个静态或类特定的私有变量(即clazz的不同实例将共享相同的'c'变量)。它可以在任何clazz实例中作为'c'访问,并且clazz实例中的更改会反映在clazz的所有实例中。

d是一个静态/类特定的公共变量。它可以通过'clazz.prototype.d'或'myClazz.prototype.d'从任何地方访问。

我对变量方案的理解的总体问题是,没有办法声明非静态的私有变量(即每个类的实例的唯一版本)。

第二个问题是关于不同类型的类声明。

我一直在使用:

var MySingleton = new function() {...};

创造单身人士。它是否正确?我也不确定在这种情况下“new”关键字的效果以及在声明结尾附加()函数括号如下:

var MySingleton = new function() {...}();

我一直在使用这种模式来声明一个类,然后实例化该类的实例:

function myClass() {...};
var classA = new myClass();
var classB = new myClass();

这是正确的方法吗?

2 个答案:

答案 0 :(得分:19)

您适合ab

a是一个参数,仅在constructor function范围内可用。

b是一个公共实例变量,可在使用该构造函数创建的所有实例上使用。

c是一个私有变量,只能在构造函数中访问。

d声明无效,因为prototype对象仅用于constructor functions,如Clazz.prototype.d = 3;,如果您这样做,变量将被共享,但您可以为特定实例分配值,默认值为 shadowed (通过原型链)。

对于“私人变量”,您可以使用声明c的方式,例如:

function Clazz(){
    var c = 3; // private variable

    this.privilegedMethod = function () {
      alert(c);
    };
}

特权方法是公共的,但是它们可以访问构造函数内声明的“私有”变量。

对于创建单例,最简单的方法是使用对象文字,例如:

var myInstance = {
  method1: function () {
    // ...
  },
  method2: function () {
    // ...
  }
};

如果你想在你的单例实例上拥有私人成员,你可以:

var myInstance = (function() {
  var privateVar = '';

  function privateMethod () {
    // ...
  }

  return { // public interface
    publicMethod1: function () {
      // all private members are accesible here
    },
    publicMethod2: function () {
    }
  };
})();

这被称为模块模式,它基本上允许您通过利用closures将私有成员封装在对象上。

更多信息:

修改:关于您发布的语法:

var mySingleton = new (function() {
  // ...
})();

通过使用new运算符,您将在一步中声明并使用“匿名构造函数”,这将生成一个新的对象实例,它是有效的,但我个人更喜欢“模块”模式方法,以创建我自己的对象实例(并避免new)。

此外,阅读new function () {},我认为如果您不太了解new运算符的工作原理,那么这种情况并不直观,可能会产生混淆。

关于括号,它们是可选的,如果你不添加它们,new运算符将调用没有参数的函数构造函数(参见ECMA-262,11.2.2 )。

答案 1 :(得分:3)

好的,让我们回过头来看看:

  1. 'a'是传递给类的构造函数的参数。它只会在构造函数的调用期间存在。这意味着您应该将其值存储在某处。

  2. 'b'是公共实例成员。它是特定于实例的(虽然,因为您在构造函数中分配值,所有实例最初将具有相同的'b'值)。

  3. 'c'是私有实例成员。但是,它只能在构造函数中访问,因为它只在该范围内定义。除非你从构造函数中的闭包中引用它,否则它的命运将类似于上面'a'的命运。

  4. 'd'是公共实例成员。您的类的每个实例最初都会有一个成员'd',其值为4。但请注意,将引用类型对象分配给类的原型成员(例如“d”)将使每个实例成员“d”引用同一对象。例如:

    MyClass.prototype.d = { prop1: 'val1', prop2: 'val2' };        
    var a = new MyClass();
    var b = new MyClass();        
    a.d.prop1 = 'foo'; // is the same as: b.d.prop1 = 'foo';
    
  5. 该类的静态成员使用:

    定义
    function MyClass()
    {
      // ...
    }    
    MyClass.staticMemeber = 'I am a static member';
    

    您可能不应该将MyClass.prototype视为保存静态成员/方法的位置。分配给类原型的所有内容又是其每个实例的成员。

  6. 当()附加到函数定义(块后面)时,执行该函数。这意味着:

    var myFunc = function() { alert('blah'); }();
    

    只会导致方法调用。以下代码:

     var MySingleton = new function() {...}();
    

    意味着'使用function()的返回值作为MySingleton的构造函数。