2

我的问题是关于维护其父对象原型链的子对象。

在 John Resig 的高级 Javascript 幻灯片 ( http://ejohn.org/apps/learn/#76 ) 中,他写道,为了维护子对象的原型链,您必须实例化一个新的父对象。

然而,通过几个快速测试,我注意到原型链是通过将子对象原型设置为等于父对象原型来维护的。

任何澄清将不胜感激!

原始代码

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" );

我的修改版

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();
4

2 回答 2

8

在 John Resig 提供的代码中,他首先设置Ninja.prototypePerson.prototype. 然后他立即将其重置为{ dance: Person.prototype.dance }

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

结果是Ninja构造函数创建的任何对象都将直接继承{ dance: Person.prototype.dance }不是Person.prototype. 因此(new Ninja) instanceof Person将返回false。在这种情况下,原型链是:

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

在修改后的版本中,您删除了第二个分配到Ninja.prototype,有效地设置Ninja.prototypePerson.prototype。因此原型链是:

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

请注意,since与两者Ninja.prototype相同,并且将返回。这是因为操作符依赖于构造函数Person.prototype(new Ninja) intanceof Ninja(new Ninja) instanceof Persontrueinstanceofprototype

然而,在 JavaScript 中实现继承的正确方法是设置Ninja.prototypeObject.create(Person.prototype)(或以老派的方式设置为new Person),在这种情况下,原型链将是:

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

注意:永远记住,在 JavaScript 中对象继承自其他对象。它们从不继承构造函数。如果您想了解 JavaScript 中真正的原型继承,请阅读我的博客文章,了解为什么原型继承很重要

于 2013-07-21T02:45:04.223 回答
1

如果您不喜欢 JavaScript 中的原型设计方式以实现您的需求,我建议您看一下:https ://github.com/haroldiedema/joii

它基本上允许您执行以下操作(以及更多):

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
于 2014-01-22T16:13:47.223 回答