1
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

8
  • Yes, it is possible, however instanceof might not work as expected then. What do you actually want to do? That "function switch" sounds like a bad idea. Are you sure you don't want to "subclass" Person? Commented Dec 22, 2013 at 21:14
  • @Bergi I want some sort of functionality where I have a method that can take a manager, janitor and president object which inherit from Person. How should I differentiate between those types? Should I use something like hasOwnProperty instead of switching on the prototype? Commented Dec 22, 2013 at 21:17
  • Inheriting three times from Person sounds like the right thing - but then they don't have the same prototype ("share"). Whether it's better to distinguish the instances by calling their own methods or by instanceof-checking them should be another question. Commented Dec 22, 2013 at 21:23
  • @Bergi so let's say that the personChecker function appends the firstName and lastName properties on the page, but it does so in a different color depending on the person, manager, etc. How would that be implemented? Would I switch on to be able to tell the difference? Commented Dec 22, 2013 at 21:28
  • @wootscootinboogie: You could always add an extra field to your objects to tell what class they belong to. So you would do this.personType = "JANITOR", this.personType = "MANAGER", etc. Commented Dec 22, 2013 at 21:30

3 Answers 3

2

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).

Sign up to request clarification or add additional context in comments.

3 Comments

Interesting, I think this is what I really wanted to do. What are some of the more subtle problems this antipattern causes?
I think the most common problem is that anything the constructor does with this will happen to your new prototype object, when the assumption is probably that this is just an instance object.
Thank you, This is the best explanation I've come across yet!
2

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)

2 Comments

Instead of that helper function, you should just use Object.create or a shim of it (@DaggNabbit: it's OK here, because he uses blank explicitly, although some explanation would've helped)
That's nice @Bergi, I didn't know that. IE9 upward but still. I'll add it to my answer
1

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.

2 Comments

-1 Why are all your managers called jon doe? Don't use new for inheritance!
@Bergi I thought that wootscootinboogie wanted "jon doe" to be a default name

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.