2009-11-30 76 views
10

我对JS比较陌生,我遇到了正确模拟OOP原则的问题。JavaScript类和可变范围

我想我有两个问题。质疑第一个是关于许多方法来声明变量。

说我有一个类:

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

var myClazz = new clazz(1); 

我是正确的以下评估:

一个是私有变量,例如特定的(即不同clazz中的情况下,将具有独特的变量和自变量'一个')。它可以从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() {...}; 

创建单身。它是否正确?我也不能确定为在这种情况下,“新”的关键字的效果以及追加()函数括号来声明的结尾像这样:

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

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

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

这是正确的方法吗?

回答

18

你为ab是正确的:

a一种说法,只有constructor function的范围内使用。

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

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

d声明是无效的,因为prototype对象是指只能使用于constructor functions,像Clazz.prototype.d = 3;,如果你像这样做,变量会被共享的,但你可以在一个特定的实例分配一个值,并且默认值将为被遮蔽(通过原型链)。

对于“私有变量”你可以用你声明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)。

+2

+1。一个非常完整和信息丰富的答案。 – 2009-11-30 23:51:17

+0

谢谢您提供的信息。 后续工作:单件声明的模块方法和原始文章中引用的样式之间的有形差异是什么? – Cmc 2009-12-01 15:41:03

+0

** @ Lior:**谢谢!,** Cmc:**我写了一些关于你发布的语法...... – CMS 2009-12-01 17:06:59

3

OK,让我们去在这个:

  1. “一”是传递给你的类的构造函数的参数。它只会在构造函数调用期间存在。这意味着你应该在某处存储它的值。

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

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

  4. 'd'是一个公共实例成员。您的班级的每个实例最初都会有一个值为4的成员“d”。但是请注意,将引用类型对象分配给类的原型成员(如'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以保持分配给你的类的静态成员/ methods.Everything的地方'原型反过来是它的每个实例的成员。

  6. 当()被附加到函数定义(正好在块之后)时,函数被执行。这意味着:

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

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

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

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