1

Ok so I have been trying to figure out a way to make plain old Javascript have some sort of extension inheritance like many other OOP languages. But I have run into a specific problem, when a class extends a parent class using prototype each child of that object share variables rather than have their own new instance of the parent. For example:

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();

So what happens is when the code is run the console looks like this:

1
2

Where as what I would prefer is for the "num" variable being inherited from the parent class to be unique to each respective instance and thus the output should be:

1
1

I assume this happens because when prototype is called it only creates a single new instance of TestA rather than one for each time TestB's constructor is called. The problem is that I have not been able to find another way to make it work?

thanks for any help (and note this is actually for a more specific use but I just wanted to create a super simple test case to illustrate the problem cleanly. I do not have the freedom to use an external library such as jQuery or prototype.js to solve the problem)

2
  • Not sure if this can help or not: ejohn.org/blog/simple-javascript-inheritance Commented May 29, 2012 at 17:04
  • can't you just make num a property of the TestA object? this would make it public, though. Commented May 29, 2012 at 17:15

3 Answers 3

3

You are not supposed to define methods in the constructor but in the prototype. This saves memory , performs better as well as allows the class to be extended cleanly.

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
Sign up to request clarification or add additional context in comments.

3 Comments

@user1424240 yea it's pretty damn bad, the only syntactic help from the language here was new :P
Ya ;) Im used to actionscript where I can just declare "extends". Hey another question, how would override methods be declared if I want to call the previous super? for example: TestB.prototype.count{//Call TestA count method here };
@user1424240 in the child class method: TestA.prototype.count.call(this, arg1, arg2, arg3) The .call is a special method of all functions that takes the this binding as first argument. You can ofcourse manually set TestB.prototype.parent = TestA and then this.parent.prototype.count.call( this)
0

As far as I know, prototypes only come in to play when reading a property. When you edit a property via the instance and not the prototype, the instance makes it's own property of the same name and the edited value. The prototype value stays the same.

In your example, you carried over a private variable, that is not visible from the outside. Therefore, it can't be "edited" and will carry its value through all instances of the inheriting classes.

In this sample, this makes num public so that it's editable and "patchable" at the instance level.

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

Before count operations:

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)

After count operations, prototype num remains 0 and the instance will have 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)

Comments

0

The moment you write to an inherited property of an instance, a new copy of the property is created for that instance.

Fore example, suppose you have:

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

where TypeB inherits the val property from TypeA.

console.log(objB1.val);  // reads the inherited value of property val
console.log(objB2.val);  // also reads the inherited value of property val

But the moment you write that property, such as:

objB1.val = 35; // objB1 now gets a new copy of the val property.

or

objB1.val++; // objB1 now gets a new copy of the val property.

In both the above cases, when objB1.val is written, it no longer refers to the inherited property but instead a new copy of the property val is created for instance objB1

If you want to store count, one way is to share it; for convenience you can make it a property of the constructor function of your parent class. So the count function would become:

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

TestA.num = 0;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.