JavaScript 中的对象继承

Posted

技术标签:

【中文标题】JavaScript 中的对象继承【英文标题】:Object Inheritance in JavaScript 【发布时间】:2013-07-20 01:19:36 【问题描述】:

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

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

【问题讨论】:

this 可能会有所帮助 在“现代”浏览器中你会这样做:Ninja.prototype = Object.create(Person.prototype). 【参考方案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

【讨论】:

【参考方案2】:

在代码 John Resig 中,他首先将 Ninja.prototype 设置为 Person.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 ,而 dance: Person.prototype.dance 不是Person.prototype 的实例。因此(new Ninja) instanceof Person 将返回 false。在这种情况下,原型链是:

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

在修改后的版本中,您删除了对Ninja.prototype 的第二个分配,实际上将Ninja.prototype 设置为Person.prototype。因此原型链是:

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

请注意,由于Ninja.prototypePerson.prototype 相同,因此(new Ninja) intanceof Ninja(new Ninja) instanceof Person 都将返回true。这是因为instanceof operator depends on the prototype of a constructor。

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

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

注意:永远记住,在 JavaScript 中对象继承自其他对象。它们从不继承构造函数。如果您想了解 JavaScript 中真正的原型继承,请阅读我在 why prototypal inhritance matters 上的博文。

【讨论】:

很棒的博文。感谢资源!

以上是关于JavaScript 中的对象继承的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript中的DOM,BOM详细介绍;

JavaScript中的继承实现

javascript JavaScript中的面向对象继承

JavaScript 中的对象继承

JavaScript 中的字符串原语和字符串对象有啥区别?

JavaScript面向对象中的继承