1

好的,所以我一直在想办法让普通的旧 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

我假设会发生这种情况,因为当调用原型时,它只创建一个新的 TestA 实例,而不是每次调用 TestB 的构造函数时创建一个。问题是我还没有找到另一种方法让它工作?

感谢您的帮助(请注意,这实际上是为了更具体的用途,但我只是想创建一个超级简单的测试用例来清楚地说明问题。我没有使用外部库(如 jQuery 或prototype.js)的自由解决问题)

4

3 回答 3

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
于 2012-05-29T17:15:58.870 回答
0

据我所知,原型只有在读取属性时才会发挥作用。当您通过实例而不是原型编辑属性时,实例会使其成为同名的自己的属性和编辑后的值。原型值保持不变。

在您的示例中,您继承了一个从外部看不到的私有变量。因此,它不能被“编辑”,并将通过继承类的所有实例传递其值。

这个示例中,它是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)
于 2012-05-29T17:19:37.853 回答
0

当您写入实例的继承属性时,会为该实例创建该属性的新副本。

例如,假设您有:

var objB1 = new TypeB();
var objB2 = new TypeB();

其中 TypeB 继承了valTypeA 的属性。

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写入时,它不再引用继承的属性,而是val创建属性的新副本,例如 objB1

如果要存储计数,一种方法是共享它;为方便起见,您可以将其设为父类的构造函数的属性。所以计数函数将变为:

function TestA(){
    this.count = function(){
        TestA.num++;
        console.log(TestA.num);
    }
};

TestA.num = 0;

于 2012-05-29T17:57:40.327 回答