2014-04-01 73 views
4

我有我要繼承從基本功能:添加原型對象

function Base() { 
    this._dummy = 1; 
}; 
Base.prototype.notify = function() { 
    alert("Notify"); 
}; 

創建另一個構造函數類的工作:

function Concrete1() {}; 
Concrete1.prototype = new Base(); 
var concr1 = new Concrete1(); 
concr1.notify(); // alerts "Notify" 

聲明這樣一個對象不起作用,可能因爲對象不具有原型

var concrete2 = new function() {}; 
concrete2.prototype = new Base(); 
concrete2.notify(); // doesn't work 

我不希望創建Concrete2構造函數,因爲它只會是它的一個實例。

我可以用new function()方法使「繼承」工作嗎?

+0

錯字錯誤,抱歉。是'concrete2' – Catalin

回答

2

由於Base是一個構造函數,如果你想使用Base.prototype作爲它的基礎,爲Brian Peacock points out below你可以使用構造一個對象:

var concrete2 = new Base(); 
concrete2.notify(); // Works 

如果您想進一步的功能添加到concrete2例如,您可以直接做到這一點:

concrete2.doSomethingElse = function() { /* ... */ }; 

這工作,因爲你已經有一個構造函數,所以要建立由construc支持單個對象的最簡單方法tor的原型是使用new操作符。

但是,有時您希望在與構造函數沒有關聯的情況下使用對象,或者您有一個不想調用該構造函數的原因。在這些情況下(我給下面一個的例子),你可以使用Object.create,這是在ES5並且可以在舊的瀏覽器被部分勻:

// Creates an object backed by Base.prototype without calling Base 
var concrete2 = Object.create(Base.prototype); 
concrete2.notify(); // Works 

Object.create直接創建一個新對象,並設置其原型到你傳入它的對象。

if (!Object.create) { 
    Object.create = function(proto, props) { 
     if (typeof props !== "undefined") { 
      throw "The two-argument version of Object.create cannot be shimmed."; 
     } 
     function ctor() { } 
     ctor.prototype = proto; 
     return new ctor(); 
    }; 
} 

的一種用途是通過與其他一些代碼的標記了一個問題爲例:它的單參數版本可以在舊的瀏覽器,這也是有用的知道它做什麼來墊高問題,它使用一種常見但不是理想的方式來設置Concrete1Base之間的繼承關係。這是問題的行:

Concrete1.prototype = new Base();     // Not ideal 

的問題是:如果有什麼Base做一些事情,應該只有特定實例?例如,假設它接受特定於實例的參數? (這是一個,但只有一個,方法Base可能包含特定於實例的代碼。)調用Base幾乎從來都不是爲其「子類」設置原型的正確方法。相反,您使用Object.create

Concrete1.prototype = Object.create(Base.prototype); // Better 

...通常依次爲:

Concrete1.prototype.constructor = Concrete1; 

...只是因爲這是規範如何定義函數實例的原型屬性(它表示constructor將作爲函數,但實際上從未實際使用constructor)。

然後你從Concrete1函數調用Base時,其創建一個實際的實例:

function Concrete1(any, necessary, args) { 
    Base.call(this, any, necessary); // For example 
    this.args = args;    // For example 
} 

完整的示例:

function Person(firstName, lastName) { 
    this.firstName = firstName; 
    this.lastName = lastName; 
} 
Person.prototype.getFullName = function() { 
    return this.firstName + " " + this.lastName; 
}; 
/* ...further Person-specific functions put on Person.prototype here...*/ 

function Employee(firstName, lastName, jobTitle) { 
    Person.call(this, firstName, lastName); 
    this.jobTitle = jobTitle; 
} 
Employee.prototype = Object.create(Person.prototype); 
Employee.prototype.constructor = Employee; 
/* ...Employee-specific functions put on Employee.prototype here...*/ 

function Manager(firstName, lastName, jobTitle) { 
    Employee.call(this, firstName, lastName); 
    this.jobTitle = jobTitle; 
} 
Manager.prototype = Object.create(Employee.prototype); 
Manager.prototype.constructor = Manager; 
/* ...Manager-specific functions put on Manager.prototype here...*/ 

...等等。 (或者使用一個腳本像我Lineage劇本,這也有助於supercalls和簡化的東西公平一點。)

+0

看起來有趣!我將不得不和他們一起玩,以瞭解他們是如何工作的。 – Catalin

1

你的代碼包含兩個小錯誤:

  1. 當定義concrete1你不需要new關鍵字在函數前面。
  2. 您調用concrete2.notify()的方式不起作用,因爲您沒有新類的實例。 concrete2.prototype.notify()將工作,如將new concrete2().notify()

一個工作版本(有一些重命名爲清楚起見)查看this JSFiddle

編輯/重寫

謝謝@ T.J.Crowder用於指出@RaraituL一直在尋找繼承基類單身。

在大多數情況下,您可以簡單地創建一個Base的實例並修改它是您希望添加/覆蓋的屬性。雖然這不會提供原型繼承,它可能會達到預期的效果:

function Base() { 
    this._dummy = 1; 
}; 

Base.prototype.notify = function() { 
    alert("Notify"); 
}; 

Concrete1 = new Base(); 

//My Extension of Base 
Concrete1.foo = function() { 
    //Some method 
} 

此解決方案可以打破,如果你有,爲了引用父類需要一個「乾淨」的原型鏈結構的代碼。但是,這不是一個正常的用例,並且可能會非常不明確的代碼。

+0

@ T.J.Crowder好點,我想我在寫答案時處於調試模式。我正在檢查這個Object.create業務,它看起來像一個有趣的解決方案。 –