扩展Javascript类和继承

扩展Javascript类和继承,javascript,class,prototype,Javascript,Class,Prototype,好的,所以我一直在试图找到一种方法,使普通的老Javascript像许多其他OOP语言一样具有某种扩展继承。但我遇到了一个特定的问题,当一个类使用原型扩展父类时,该对象的每个子对象都共享变量,而不是拥有自己的父对象的新实例。例如: TestB.prototype = new TestA(); function TestB(){ } function TestA(){ var num = 0; this.count = function(){ num ++

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

您不应该在构造函数中定义方法,而应该在原型中定义方法。这样可以节省内存 ,性能更好,并允许干净地扩展类

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

据我所知,原型只有在读取属性时才会出现。通过实例而不是原型编辑特性时,实例将使其自己的特性具有相同的名称和编辑的值。原型值保持不变

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

在中,这将使
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)
计数操作后,prototype
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)

写入实例的继承属性时,将为该实例创建该属性的新副本

例如,假设您有:

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

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

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

TestA.num=0

不确定这是否有帮助:您不能将
num
作为
TestA
对象的属性吗?不过,这会使它公开。@user1424240是的,它非常糟糕,这里语言的唯一语法帮助是
new
:PYa;)我习惯了actionscript,在这里我可以声明“扩展”。嘿,还有一个问题,如果我想调用上一个super,如何声明重写方法?例如:TestB.prototype.count{//Call TestA count method here}@子类方法中的user1424240:
TestA.prototype.count.call(this,arg1,arg2,arg3)
the
.call
是所有函数的一种特殊方法,它将
this
绑定作为第一个参数。当然,您可以手动设置
TestB.prototype.parent=TestA
,然后
this.parent.prototype.count.call(this)
function TestA(){
    this.count = function(){
        TestA.num++;
        console.log(TestA.num);
    }
};