2013-07-21 232 views
2

我的問題是關於維護其父對象的原型鏈的子對象。JavaScript中的對象繼承

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

[這](http://stackoverflow.com/questions/5991152/why-do-we-use-boy-prototype-new-human-to-simulate-inheritance)可能會幫助 – aaronman

+1

在「現代」瀏覽器:'Ninja.prototype = Object.create(Person.prototype)'。 – elclanrs

回答

8

在約翰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  | 
+-------------------+ 

注意,因爲Ninja.prototype相同Person.prototype(new Ninja) intanceof Ninja(new Ninja) instanceof Person將返回true。這是因爲instanceof operator depends on the prototype of a constructor

但是做實現JavaScript的繼承權的辦法是設置Ninja.prototypeObject.create(Person.prototype)(或者老同學的方式來new Person),在這種情況下,原型鏈將是:

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

注:一定要記住,在JavaScript對象中繼承其他對象。它們從不從構造函數繼承。如果你想了解JavaScript中真正的原型繼承,請閱讀我的博文why prototypal inhritance matters

+0

很棒的博客文章。感謝您的資源! –

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