简体   繁体   中英

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

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)

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM