2014-06-12 46 views
1

有人能解釋下繼承的實現之間的區別:JavaScript的原型繼承案件

function Parent(name) { 
    this.name = name; 
    this.parentFoo = function() { 
     //... 
    } 
} 

function Child() { 
    this.additional = true; 
    Parent.apply(this, arguments); // Is it for copying parent fields to child object? 
} 

Child.prototype = Object.create(Parent.prototype); 

function Parent(name) { 
    this.name = name; 
} 

Parent.prototype.parentFoo = function() { 
    //.... 
} 

function Child() { 
    this.additional = true; 
    Parent.apply(this, arguments); // Is it for copying parent fields to child object? 
} 

Child.prototype = Object.create(Parent.prototype); 

我的意思是這將是更好的使用,增加功能,直接構造函數或原型?我在問,因爲

var childObj = new Child("Child name"); 
var parentObj = new Parent("Parent name"); 

childObj.foo(); 
parentObj.foo(); 

在這兩種情況下都能很好地工作。 謝謝!

回答

0

我相信不同的是後面的選項(原型)將其添加到該對象的簽名,但前者(使用本)增加了函數作爲對象的內存佔用的一部分。因此,在後一種選擇中,Parent對象具有parentFoo作爲其定義的一部分,但在前者中,父對象的每個實例都在內存中具有該函數。

1

在第一個片段中,你並沒有將你的方法存儲在Parent的原型中,所以克隆ParentChild類的原型沒有做任何事情。您仍然能夠調用從子實例parentFoo因爲你正在運行的父類的構造與孩子作爲其背景與Parent.apply(this, arguments);它運行

this.parentFoo = function() { 
    //... 
} 

文意this指子實例。

我敢肯定,重新定義並在構造函數結合你的方法是不是最佳的。

在第二個代碼片段中,您調用了子代的父代構造函數,但是您沒有將父代原型擴展到子代類,因此您將無法訪問 parentFoo方法孩子的例子。你可以修復,通過從第一個片段添加一行:

Child.prototype = Object.create(Parent.prototype); 

編輯: 兩種情況之間的差異是第一位的,你不使用典型的傳承。您將父級原型克隆到子級原型中,但是您沒有將任何密鑰附加到父級原型。相反,當您在子構造函數中調用Parent.apply(this, arguments);時,您將重新定義並直接將每個方法綁定到父構造函數中的實例。

+0

當然,我已經更新了第二個案例。我從一開始就提到它。 – sidlejinks

+0

因此,由於重新定義和重新綁定每種方法,我們在第一種情況下會出現性能損失,對嗎? – sidlejinks

+0

@sidlejinks我相信如此。 – SimpleJ

0

參見Learning JavaScript, especially class-like Constructor function and Property Inheritance through prototype/proto chaining和其中的參考文獻。在JavaScript

繼承通常由Child.prototype=new Parent();完成。

// 'function' has "prototype" property by default. 
// 'object' including 'function object' has "__proto__" property by default. 

function Employee(){ 
    // Implicitly "this.__proto__=Employee.prototype;" 
    this.name="empty"; 
    this.dept="general"; 
} 
// By default, "Employee.prototype={__proto__:Object.prototype}" 
// "(new Employee)={__proto__:Employee.prototype, name:"empty", dept:"general"}" 
Employee.prototype.a="This is 'a' in Employee.prototype"; // Additional prototype 'a'. 
// Then, "Employee.prototype={__proto__:Object.prototype, a:"Employee.prototype.a"}" 


function Manager(){ 
    // Implicitly "this.__proto__=Manager.prototype;" 
    this.reports=[]; 
} 
// "(new Manager)={__proto__:Manager.prototype, reports:[]}" 
Manager.prototype=new Employee; 
// Then, "Manager.prototype={__proto__:Employee.prototype, name:"empty", dept:"general"}" 

function WorkerBee(){ 
    // Implicitly "this.__proto__=WorkerBee.prototype;" 
    this.projects=[]; 
} 
// "(new WorkerBee)={__proto__:WorkerBee.prototype, projects:[]}" 
WorkerBee.prototype=new Employee; 
// Then, "WorkerBee.prototype={__proto__:Employee.prototype, name:"empty", dept:"general"}" 


function SalesPerson(){ 
    // Implicitly "this.__proto__=SalesPerson.prototype;" 
    this.dept="sales"; 
    this.quota=100; 
} 
// "(new SalesPerson)={__proto__:SalesPerson.prototype, dept:"sales", quota:100}" 
SalesPerson.prototype=new WorkerBee; 
// Then, "SalesPerson.prototype={__proto__:WorkerBee.prototype, projects:[]}" 

function Engineer(){ 
    // Implicitly "this.__proto__=Engineer.prototype;" 
    this.dept="engineering"; 
    this.machine="machine"; 
} 
// "(new Engineer)={__proto__:Engineer.prototype, dept:"engineering", machine:""}" 
Engineer.prototype=new WorkerBee; 
// Then, "Engineer.prototype={__proto__:WorkerBee.prototype, projects:[]}" 
+0

感謝您的詳細解釋!但我想在這種情況下,每次都會調用父對象的構造函數。如果我們不想讓它被調用呢? – sidlejinks

+0

@sidlejinks'Child.prototype =新的父();'父對象的構造函數被調用剛剛開始一次。 – kipid