扩展Javascript类和继承

时间:2012-05-29 17:00:32

标签: javascript class prototype

好的,所以我一直试图找出一种方法来使普通的旧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解决问题)

3 个答案:

答案 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;