好的,所以我一直试图找出一种方法来使普通的旧Javascript像许多其他OOP语言一样具有某种扩展继承。但是我遇到了一个特定的问题,当一个类使用原型扩展父类时,该对象的每个子项共享变量而不是拥有自己的父实例。例如:
TestB.prototype = new TestA();
function TestB(){ }
function TestA(){
var num = 0;
this.count = function(){
num ++;
console.log(num);
}
}
var test = new TestB();
test.count();
var test2 = new TestB();
test2.count();
所以会发生什么,当代码运行时,控制台看起来像这样:
1
2
我更喜欢的是从父类继承的“num”变量对每个相应的实例都是唯一的,因此输出应该是:
1
1
我认为这是因为当调用prototype时,它只会创建一个TestA的新实例,而不是每次调用TestB的构造函数时都创建一个。问题是我还没有找到另一种方法让它起作用?
感谢任何帮助(请注意这实际上是为了更具体的用途,但我只是想创建一个超级简单的测试用例来干净地说明问题。我没有自由使用外部库,如jQuery或prototype.js解决问题)
答案 0 :(得分:3)
您不应该在构造函数中定义方法,而是在原型中定义。这节省了内存 ,表现更好,并允许课程干净利落。
function TestA() {
this.num = 0;
}
TestA.prototype = {
count: function() {
console.log( this.num++ );
},
constructor: TestA
};
function TestB(){
TestA.apply( this, arguments ); //Run parent constructor when instantiating a child
}
TestB.prototype = Object.create( TestA.prototype ); //Don't invoke the constructor when merely establishing inheritance
var test = new TestB();
test.count(); //0
var test2 = new TestB();
test2.count(); //0
答案 1 :(得分:0)
据我所知,原型只在阅读房产时才会出现。当您通过实例而不是原型编辑属性时,实例会使其具有相同名称和编辑值的属性。原型值保持不变。
在您的示例中,您携带了一个私有变量,该变量在外部不可见。因此,它不能被“编辑”,并且将通过继承类的所有实例传递其值。
在this sample中,这会使num
公开,以便在实例级别进行编辑和“修补”。
var test, test2;
function TestA() {
this.num = 0; //public num
this.count = function() {
this.num++;
console.log(this.num);
}
}
function TestB() {} //instances of TestB don't have properties
TestB.prototype = new TestA();
test = new TestB();
test2 = new TestB();
//monitor the instances
console.log(test);
console.log(test2);
test.count(); //these create a num property at the instance level
test2.count(); //but the prototype num remains 0
test2.count();
test2.count(); //test will have 1 and test2 will have 3
在计数操作之前:
Object -> TypeA -> TypeB -> test
'-> num = 0 '->num = 0 (from TypeA)
'-> count() '->count() (from TypeA)
Object -> TypeA -> TypeB -> test2
'-> num = 0 '->num = 0 (from TypeA)
'-> count() '->count() (from TypeA)
计数操作后,原型num
保持为0,实例将有num
:
Object -> TypeA -> TypeB -> test
'-> num = 0 '->num = 1 (on the instance)
'-> count() '->count() (from TypeA)
Object -> TypeA -> TypeB -> test2
'-> num = 0 '->num = 3 (on the instance)
'-> count() '->count() (from TypeA)
答案 2 :(得分:0)
当您写入实例的继承属性时,会为该实例创建该属性的新副本。
例如,假设你有:
var objB1 = new TypeB();
var objB2 = new TypeB();
其中TypeB从TypeA继承val
属性。
console.log(objB1.val); // reads the inherited value of property val
console.log(objB2.val); // also reads the inherited value of property val
但是你写这个属性的那一刻,例如:
objB1.val = 35; // objB1 now gets a new copy of the val property.
或
objB1.val++; // objB1 now gets a new copy of the val property.
在上述两种情况下,当写入objB1.val
时,它不再引用继承的属性,而是为例如objB1创建属性val
的新副本
如果你想存储计数,一种方法是分享它;为方便起见,您可以将其作为父类的构造函数的属性。因此count函数将变为:
function TestA(){
this.count = function(){
TestA.num++;
console.log(TestA.num);
}
};
TestA.num = 0;