5

Say I have a classe in JS with prototype functions...

function Foo() {
    this.stuff = 7;
    this.otherStuff = 5;
}

Foo.prototype.doSomething = function() { };

Foo.prototype.doSomethingElse = function() { };

Now say I want to "extend" this class by subclassing it. In Java this would look like...

public class Bar extends Foo {}

Now I know in JS there really isn't a concept of class, everything can be altered and it all really just boils down to a crap-ton of dictionaries but nonetheless, I should be able to copy the prototype of one class and append it to the prototype of another, right?

What would the code for something like that look like in vanilla JS?

1

4 Answers 4

5

One of the way is like below,

function Foo() {
    this.stuff = 7;
    this.otherStuff = 5;
}
Foo.prototype.doSomething = function() { alert("some"); };

Foo.prototype.doSomethingElse = function() { };

function Bar() {
   Foo.call(this); // this line
}
Bar.prototype = Object.create(Foo.prototype);

var b = new Bar();
b.doSomething(); 
Sign up to request clarification or add additional context in comments.

4 Comments

Whoa what does Foo.call(this); do?
call is used to chain constructors for an object. more
Ahh cool! So that will run Foo's constructor? Kind of like super() in Java?
Not sure. But don't use java concepts with javascript to learn javascript. They both are different and are OOP based. Each has its own way getting things done. I recommend you to go in that way.
3

The solution that mohkhan provided is outdated. The new way to do inheritance is:

function Bar() {
    Foo.call(this, /* additional arguments if required */);
}

Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.constructor = Bar;              // don't forget to do this

If you want to make your code look more classical then take a look at the augment method. Using augment you can write the above code as:

var Bar = Foo.augment(function (base) {
    this.constructor = function () {
        base.constructor.call(this, /* additional arguments if required */);
    };
});

The augment method itself is just seven lines of code:

Function.prototype.augment = function (body) {
    var base = this.prototype;
    var prototype = Object.create(base);
    body.apply(prototype, Array.prototype.slice.call(arguments, 1).concat(base));
    if (!Object.hasOwnProperty.call(prototype, "constructor")) return prototype;
    var constructor = prototype.constructor;
    constructor.prototype = prototype;
    return constructor;
};

Seriously, use the new way. It's better. Here's why: Javascript inheritance: calling Object.create when setting a prototype

Comments

2

Something like this...

function Bar(){
    // your code
}

Bar.prototype = new Foo(); // Bar extends Foo

4 Comments

Would this also copy the stuff and otherstuff members or just the functions?
No, it would copy the variables also, not just the functions.
In Bar you forgot to call Foo.call(this); to make Foo's variables declared as this a part of the newly created Bar: stackoverflow.com/questions/16063394/…
Don't use new to create the prototype object! Admittedly, this answer is from 2013 where this was even more common, but it's wrong nonetheless. ES5 did exist even then.
2

The accepted answer will definitely do the trick. And this "short" explanation turned into a ramble, but hopefully it's helpful.

There's one thing you have to be aware of with the accepted answer. When basically "inheriting" by doing Bar.prototype = new Foo() you're calling the constructor. So, if you have code in your constructor that isn't expecting to be used as a launch pad for another "class" you'll wind up with weird effects. Take for instance:

var Person = function (firstName, lastName) {
    ....
};

var Student = function (firstName, lastName, grade) {
    ....
};

Let's say that Student is an extension of Person. How are you going to build the prototype up on Student? Probably not like Student.prototype = new Person("John", "Doe");

A different way of handling it, which is a bit more complex but can be wrapped inside of another function is as follows:

var extend = function (child, parent) {
    var f = function () {};
    f.prototype = parent.prototype;
    child.prototype = new f();
    child.prototype.constructor = parent;
}

var Person = function (firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
}
Person.prototype.getName = function () {
    return this.firstName + " " + this.lastName;
}
Person.prototype.setAge = function (age) {
    this.age = age;
}


var Student = function (firstName, lastName, grade) {
    Person.call(this, firstName, lastName);
    this.grade = grade;
};

extend(Student, Person); //<< do this before adding stuff to the prototype

Student.prototype.getName = function () {
    var name = Person.prototype.getName.apply(this);
    return name + ", Grade " + this.grade;
}
Student.prototype.tooOldToBeAStudent = function () {
    if(this.age > 18) { return true; }
}

var p = new Person("Joe", "DiMaggio");
var s = new Student("Jack", "Sparrow", 12);
console.log(p.getName(), s.getName());
//consoles "Joe DiMaggio" "Jack Sparrow, Grade 12"
console.log(s instanceof Person); 
//true - even with the weird looking inheritance, Student is still an instance of Person.
s.setAge(30);
console.log(s.age);
//30, just like what you'd expect with a Person object.
console.log(s.tooOldToBeAStudent);
//true - as mentioned previously, 'age' is set via its inherited method.

This gets you not only the Person functionality, but allows you to build on it. Kind of like what you actually do with inheritance.

How does it work? Great question. First, objects are assigned around [basically] by reference. The prototype is an object. So, in the extend function, I create a blank function that will serve as the surrogate for the child. This copies the parent's prototype to itself, and then makes a new instance of itself the prototype of the child. This way the parent's constructor isn't called, but the parent's prototype is still used. To make sure that instanceof still works, the child.prototype.constructor is set to the parent - effectively informing javascript that the thing the child came from is the parent, rather than from the surrogate.

Also, when overriding methods, you can use the "class" you are inheriting from's prototype method and apply or call it with this - that runs the method with the scope of the current object, and you can pass any arguments you feel like however they are accepted by the function you choose. For example, Person.prototype.getName.apply(this); runs the Person's getName in the context of the current instance of the student. Let's say we wanted to override the setAge to simply console.log out the age.

Student.prototype.setAge = function () {
    Person.prototype.setAge.apply(this, arguments);
    console.log(this.age);
}

What's happening here is the Person's setAge is being called with the arguments that were passed to the Student's setAge. So, it basically allows the stuff to pass through without you having to know about the details of the original method's arguments.

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.