最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Object Inheritance in JavaScript - Stack Overflow

programmeradmin2浏览0评论

My question is regarding a child object maintaining the prototype chain of its parent object.

In John Resig's Advanced Javascript slides () he writes that in order to maintain the prototype chain of a child object you must instantiate a new parent object.

However through a couple quick tests I noticed that the prototype chain is maintained by just setting the child object prototype equal to the parent object prototype.

Any clarification would be greatly appreciated!

Original Code

function Person(){}
Person.prototype.dance = function(){};

function Ninja(){}

// Achieve similar, but non-inheritable, results
Ninja.prototype = Person.prototype;
Ninja.prototype = { dance: Person.prototype.dance };

assert( (new Ninja()) instanceof Person, "Will fail with bad prototype chain." );

// Only this maintains the prototype chain
Ninja.prototype = new Person();

var ninja = new Ninja();
assert( ninja instanceof Ninja, "ninja receives functionality from the Ninja prototype" );
assert( ninja instanceof Person, "... and the Person prototype" );
assert( ninja instanceof Object, "... and the Object prototype" );

My Modified Version

function Person(){}
Person.prototype.dance = function(){console.log("Dance")};

function Ninja(){}

// Achieve similar, but non-inheritable, results
Ninja.prototype = Person.prototype;

assert( (new Ninja()) instanceof Person, "Will fail with bad prototype chain." );

var ninja = new Ninja();
assert( ninja instanceof Ninja, "ninja receives functionality from the Ninja prototype" );
assert( ninja instanceof Person, "... and the Person prototype" );
assert( ninja instanceof Object, "... and the Object prototype" );
ninja.dance();

My question is regarding a child object maintaining the prototype chain of its parent object.

In John Resig's Advanced Javascript slides (http://ejohn/apps/learn/#76) he writes that in order to maintain the prototype chain of a child object you must instantiate a new parent object.

However through a couple quick tests I noticed that the prototype chain is maintained by just setting the child object prototype equal to the parent object prototype.

Any clarification would be greatly appreciated!

Original Code

function Person(){}
Person.prototype.dance = function(){};

function Ninja(){}

// Achieve similar, but non-inheritable, results
Ninja.prototype = Person.prototype;
Ninja.prototype = { dance: Person.prototype.dance };

assert( (new Ninja()) instanceof Person, "Will fail with bad prototype chain." );

// Only this maintains the prototype chain
Ninja.prototype = new Person();

var ninja = new Ninja();
assert( ninja instanceof Ninja, "ninja receives functionality from the Ninja prototype" );
assert( ninja instanceof Person, "... and the Person prototype" );
assert( ninja instanceof Object, "... and the Object prototype" );

My Modified Version

function Person(){}
Person.prototype.dance = function(){console.log("Dance")};

function Ninja(){}

// Achieve similar, but non-inheritable, results
Ninja.prototype = Person.prototype;

assert( (new Ninja()) instanceof Person, "Will fail with bad prototype chain." );

var ninja = new Ninja();
assert( ninja instanceof Ninja, "ninja receives functionality from the Ninja prototype" );
assert( ninja instanceof Person, "... and the Person prototype" );
assert( ninja instanceof Object, "... and the Object prototype" );
ninja.dance();
Share Improve this question asked Jul 21, 2013 at 2:01 Mr. SmeeMr. Smee 96012 silver badges28 bronze badges 2
  • 1 this might help – aaronman Commented Jul 21, 2013 at 2:05
  • 1 In "modern" browsers you'd do: Ninja.prototype = Object.create(Person.prototype). – elclanrs Commented Jul 21, 2013 at 2:06
Add a ment  | 

2 Answers 2

Reset to default 8

In the code John Resig provided he first sets Ninja.prototype to Person.prototype. Then he immediately resets it to { dance: Person.prototype.dance }:

// Achieve similar, but non-inheritable, results
Ninja.prototype = Person.prototype;
Ninja.prototype = { dance: Person.prototype.dance };

The result is that any object created by the Ninja constructor will directly inherit from { dance: Person.prototype.dance } which is not an instance of Person.prototype. Hence (new Ninja) instanceof Person will return false. In this case the prototype chain is:

        null
         ^
         |
         | [[prototype]]
         |
+------------------+
| Object.prototype |
+------------------+
         ^
         |
         | [[prototype]]
         |
+------------------+
|  Ninja.prototype |
+------------------+
         ^
         |
         | [[prototype]]
         |
+------------------+
|     new Ninja    |
+------------------+

In the modified version you remove the second assignment to Ninja.prototype, effectively setting Ninja.prototype to Person.prototype. Hence the prototype chain is:

         null
          ^
          |
          | [[prototype]]
          |
+-------------------+
|  Object.prototype |
+-------------------+
          ^
          |
          | [[prototype]]
          |
+-------------------+
| Ninja.prototype / |
| Person.prototype  |
+-------------------+
          ^
          |
          | [[prototype]]
          |
+-------------------+
|     new Ninja     |
+-------------------+

Notice that since Ninja.prototype is the same as Person.prototype both (new Ninja) intanceof Ninja and (new Ninja) instanceof Person will return true. This is because the instanceof operator depends on the prototype of a constructor.

However the right way to do achieve inheritance in JavaScript would be to set Ninja.prototype to Object.create(Person.prototype) (or in the old school way to new Person), in which case the prototype chain would be:

        null
         ^
         |
         | [[prototype]]
         |
+------------------+
| Object.prototype |
+------------------+
         ^
         |
         | [[prototype]]
         |
+------------------+
| Person.prototype |
+------------------+
         ^
         |
         | [[prototype]]
         |
+------------------+
|  Ninja.prototype |
+------------------+
         ^
         |
         | [[prototype]]
         |
+------------------+
|     new Ninja    |
+------------------+

Note: Always remember that in JavaScript objects inherit from other objects. They never inherit from constructor functions. If you wish to learn about true prototypal inheritance in JavaScript then read my blog post on why prototypal inhritance matters.

If you don't like the way prototyping works in JavaScript in order to achieve what you need, I'd suggest taking a look at this: https://github./haroldiedema/joii

It basically allows you to do the following (and more):

var Employee = new Class(function() {
    this.name = 'Unknown Employee';
    this.role = 'Employee';
});

var Manager = new Class({ extends: Employee }, function()
{
    // Overwrite the value of 'role'.
    this.role = 'Manager';

    // Class constructor to apply the given 'name' value.
    this.__construct = function(name) {
        this.name = name;
    }
});

var myManager = new Manager("John Smith");
console.log( myManager.name ); // John Smith
console.log( myManager.role ); // Manager
发布评论

评论列表(0)

  1. 暂无评论