wootscootinboogie
wootscootinboogie

Reputation: 8695

Prototypal inheritance chain with JavaScript

function Person(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
}
Person.prototype.talk = function () {
    return this.firstName + " " + this.lastName;
}
//creating a Person object for extension
var manager = new Person('jon', 'doe');
console.log(manager.talk());
//Manager prototype..but doesn't inherit Person methods 
function Manager(firstName, lastName, accessCode) {
    //shared properties
    this.firstName = firstName;
    this.lastName = lastName;

    this.accesscode = accessCode;
}
function personChecker(person) {
    var returnCode = 0;
    if (person instanceof Person) {
        returnCode = 1;
    }
    else if (person instanceof Manager) {
        returnCode = 2;
    }
    return returnCode;
}
console.log(personChecker(manager));

Is it possible to share a prototype and have a different constructor? I would like to have Manager inherit everything from Person (and then extend it) and have a function switch on the prototype and do something different depending on the argument passed to the personChecker function

Upvotes: 1

Views: 245

Answers (3)

Stuart Wakefield
Stuart Wakefield

Reputation: 6414

The typical way to support this inheritance:

// create a blank function to pass the prototype
var blank = function() {};

// assign the prototype to inherit to the blank constructor
blank.prototype = Person.prototype;

// pass an instance of the prototype as the Manager prototype
Manager.prototype = new blank();

var person = new Person('John', 'Doe');
var manager = new Manager('Greg', 'Smith', 'access1234');

manager.talk(); // Greg Smith
person.talk(); // John Doe

Here is a fiddle: http://jsfiddle.net/XF28r/

Note a Manager is also a Person so you need to switch the check around.

function personChecker(person) {
    var returnCode = 0;
    if (person instanceof Manager) {
        returnCode = 2;
    } else if (person instanceof Person) {
        returnCode = 1;
    }
    return returnCode;
}

Although note I would put this in a helper method:

function extend(parent, child) {

  var blank = function() {};
  blank.prototype = parent.prototype;
  child.prototype = new blank();
}

So then you can simply use it:

extend(Person, Manager);

As Bergi has mentioned in the comments, this can also be reduced down to:

function extend(parent, child) {
  child.prototype = Object.create(parent.prototype);
}

(works IE 9 upward)

Upvotes: 2

Dagg Nabbit
Dagg Nabbit

Reputation: 76766

In JavaScript, inheritance is generally done like this:

Manager.prototype = Object.create(Person.prototype);

Object.create creates a new object with the object passed as the first argument in its prototype chain.

If you need to support old browsers that don't have Object.create, you can do the "prototype dance" instead:

function F(){}
F.prototype = Person.prototype;
Manager.prototype = new F();

In any case, avoid code calling the constructor to get such an object (Manager.prototype = new Person()), this is a well-known antipattern and will break as soon as your constructor relies on any of its arguments (and it causes other, more subtle problems).

Upvotes: 2

Oriol
Oriol

Reputation: 288530

Use the following:

function Person(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
}
Person.prototype.talk = function () {
    return this.firstName + " " + this.lastName;
}

function Manager(firstName, lastName, accessCode) {
    //shared properties
    this.firstName = firstName;
    this.lastName = lastName;

    this.accesscode = accessCode;
}
Manager.prototype = new Person('jon', 'doe');

function personChecker(person) {
    var returnCode = 0;
    if (person instanceof Manager) {
        returnCode = 2;
    }
    else if (person instanceof Person) {
        returnCode = 1;
    }
    return returnCode;
}

Note that I have changed the order of the conditionals, because an instance of Manager is an instance of Person too:

var per = new Person('A', 'B');
per.talk();              // 'A B'
per instanceof Person;   // true
per instanceof Manager;  // false
personChecker(per);      // 1

var man = new Manager('A', 'B');
man.talk();              // 'A B'
man instanceof Person;   // true !!!!
man instanceof Manager;  // true !!!!
personChecker(man);      // 2

If you want to do it the good way, instead of

Manager.prototype = new Person('jon', 'doe');

use

Manager.prototype = Object.create(Person.prototype, {constructor: {value: Manager}});

but it doesn't work on old browsers.

Upvotes: 1

Related Questions