2014-01-26 384 views
9

我想在JavaScript中調平(我沒有在工作中使用它),並且很好地將我的頭包裹在構造函數中,以及如何實例化從它們繼承屬性的新對象。什麼是原型繼承的真實例子?

但通常要真正學到一些東西,我需要在我正在開發的一個真實項目中使用它,並在行動中看到它。

問題是,一切我讀使用像這樣的例子來解釋繼承:

function Apple (type) { 
    this.type = type; 
    this.color = "red"; 
    this.getInfo = getAppleInfo; 
} 

function Car(model, year, miles) { 

    this.model = model; 
    this.year = year; 
    this.miles = miles; 

    this.toString = function() { 
    return this.model + " has done " + this.miles + " miles"; 
    }; 
} 

function makeBaby(parent, name) { 

    var baby = Object.create(parent); 

    baby.name = name; 

    return baby; 
} 

正如你可能想象,這些類型(水果,汽車和家長)的例子對於學習概念的目的肯定有幫助,但不是真的把它們付諸實踐。

有沒有人有一個原型繼承如何在生產級別的Web應用程序中工作的例子?

+0

看看[一些JavaScript庫是否使用原型系統的動態方面?](http://stackoverflow.com/questions/10609822/does-some-javascript-library-use-dynamic-aspects-of-原型系統) – Bergi

回答

4

這不僅僅是原型繼承,而且用例也適用於經典繼承。

通常,您想要將一個類的屬性和功能擴展到另一個類。一個很好的例子就是視圖類。它有一個draw方法繪製到屏幕上。一種重用代碼的好方法。

因此,您不需要手動複製一個類的所有屬性到另一個類,而只需從基類擴展,就可以擁有它的所有功能以及添加自己的實現。

的示例代碼使用繼承:

/** 
* View1 
*/ 
function View1 { 
    this.viewId = 'view-1'; 
    this.template = '<some html here>' 
} 

View1.prototype.draw = function() { 
    var ourView = document.getElementById(this.viewId); 

    // ps. I know this is redundant, but it's here for illustration purposes. 
    var newElement = document.createElement('div'); 
    ourView.appendChild(newElement); 

    ourView.innerHTML = this.template; 
} 


/** 
* View2 
*/ 
function View2 { 
    this.viewId = 'view-2'; 
    this.template = '<some html here>' 
} 

View2.prototype.draw = function() { 
    var ourView = document.getElementById(this.id); 

    // ps. I know this is redundant, but it's here for illustration purposes. 
    var newElement = document.createElement('div'); 
    ourView.appendChild(newElement); 

    ourView.innerHTML = this.template; 
} 

正如你可以在上面看到,有很多重複的代碼。

相比之下,與代碼使用繼承:

/** 
* View1 
*/ 
function View1 { 
    this.viewId = 'view-1'; 
    this.template = '<some html here>' 
} 

View1.prototype.draw = function() { 
    var ourView = document.getElementById(this.viewId); 

    // ps. I know this is redundant, but it's here for illustration purposes. 
    var newElement = document.createElement('div'); 
    ourView.appendChild(newElement); 

    ourView.innerHTML = this.template; 
}; 

/** 
* View2 
*/ 
function View2 { 
    this.viewId = 'view-2'; 
    this.template = '<some html here>' 
} 

View2.prototype = View1.prototype; 

視圖2從來沒有需要從視圖1重新實現代碼。相反,它只是重用它。

+0

這是非常有用的......我真的被困在聲明作爲構造函數(在這種情況下,viewId和模板)的一部分之間的差異,以及作爲構造函數原型的一部分聲明的屬性這種情況下,繪製方法)。你真的很好地解釋了這種差異。謝謝你花時間! –

3

原型繼承在任何想要使用面向對象方法和繼承來模擬問題的地方都很有用。

一個很好的例子是Backbone.js如何提供基礎類,如模型,集合和視圖。在您的應用程序擴展這些基類做一些具體的事情,例如

var ProfileSummary = Backbone.View.extend({ 
    render: function() { 
    this.$el.html("Profile summary view"); 
    } 
}); 

現在ProfileSummary是具有(繼承)的所有Backbone.View方法和功能的類,但你捏捏render功能做什麼。

注意,extend方法是爲您提供任何簡單的方法使用原型繼承來擴展這些類的骨幹道路 - 看到代碼的詳細信息https://github.com/jashkenas/backbone/blob/e6f8f7ea69370b0891cc969a2c68ebb78ad6e49b/backbone.js#L1551-L1588

你可以在你的類層次結構如果創建幾層幫助你的應用程序例如。

var MyBaseView = Backbone.View.extend({ 
    //common functionality in all views within yur app 
}); 

var ProfileSummary = MyBaseView.extend({ 
    //functionality specific to the profile summary view 
}); 

var ProfileSummaryEditor = ProfileSummary.extend({ 
    //makes the profile summary editable 
}); 

希望這會有所幫助。如果我誤解了你的問題,請告訴我。

+0

這真的很有趣。我從來沒有想過擴展在原型繼承中有用。我真的只是用它來合併配置對象,但現在你用PI來談論它,很明顯它們是如何連接起來的。另外,我真的很感謝你把它放在骨幹上。這正是我期待的'真實世界'例子。我們在工作中不使用主幹,但是您所說的實際上爲我們使用的MVVM揭示了光芒。非常感謝您花時間回答。 –

+0

請注意,合併對象的_.extend和Backbone的原型擴展是不同的。前者簡單地將字段從一個對象複製到另一個對象,但後者處理原型和構造函數以及其他東西。事實上,他們是相互關聯的,而不是完全一樣的東西。 – Karolis

+0

明白了。謝謝:) –