我对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();
这是正确的方法吗?
答案 0 :(得分:19)
您适合a
和b
:
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)
好的,让我们回过头来看看:
'a'是传递给类的构造函数的参数。它只会在构造函数的调用期间存在。这意味着您应该将其值存储在某处。
'b'是公共实例成员。它是特定于实例的(虽然,因为您在构造函数中分配值,所有实例最初将具有相同的'b'值)。
'c'是私有实例成员。但是,它只能在构造函数中访问,因为它只在该范围内定义。除非你从构造函数中的闭包中引用它,否则它的命运将类似于上面'a'的命运。
'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';
该类的静态成员使用:
定义function MyClass()
{
// ...
}
MyClass.staticMemeber = 'I am a static member';
您可能不应该将MyClass.prototype视为保存静态成员/方法的位置。分配给类原型的所有内容又是其每个实例的成员。
当()附加到函数定义(块后面)时,执行该函数。这意味着:
var myFunc = function() { alert('blah'); }();
只会导致方法调用。以下代码:
var MySingleton = new function() {...}();
意味着'使用function()的返回值作为MySingleton的构造函数。