2013-07-11 103 views
2

我正在將我在Flash/AS3.0中設計的遊戲重寫爲JavaScript,並且在學習類時遇到了困難,我無法將原型包裝在原型中。我已經閱讀了大量關於它的信息,但我仍然不確定如何將其應用於此場景。JavaScript遊戲級別繼承

所以......在我的AS3.0項目中,我有一個關卡類,它具有遊戲各個層次發生的事情,Enter_Frame功能等等。然後我將這個類擴展到每個關卡的級別具體的細節,如項目的位置,地形細節等......所以我的問題是如何做到這一點最有效率和「適當」的方式。

現在我有兩個功能:

function level() { 
//generic level functionality 
} 

function level1() { 
//level1 specific functionality 
} 

接着,當我讀過,我應該我已經設置

level1.prototype = new level(); 

但我發現在運行時的水平函數中執行這一切,我不想要。理想情況下,我想要一個啓動按鈕來實例化level1,而level1有屬性和方法級別 - 如果可能的話,執行level1和level的構造函數中的所有東西,這種情況發生時可能嗎?

我確定這很明顯,但我似乎無法點擊,對不起,如果我問一個愚蠢的問題。 非常感謝任何幫助提前。

+0

在這個答案有另一種解決方案來設置繼承而不調用不使用Object.create的構造函數:http://stackoverflow.com/questions/16063394/prototypical-inheritance-writing-up/16063711#16063711 – HMR

+0

@HMR我認爲我在寫這篇文章之前偶然發現了這個問題,但你說得對,它和凱文斯的回答很相似,我猜測並且會起作用。謝謝你的幫助! – Josh

回答

2

爲了避免建立繼承時執行的構造,可以使用Object.create()

level1.prototype = Object.create(level.prototype); 

雖然, 「」 構造函數調用,你」我也需要calllevellevel1之內:

function level1() { 
    level.call(this); 

    // ... 
} 

使用call讓你沿着這樣兩個構造與同一個對象的工作通過上下文(this)。

+0

儘管我沒有完全理解它,但這正是我想要的。我需要做更多的閱讀才能正確理解「this」指向什麼時候等等。但是,非常感謝您的回答,您幫助我跨越了障礙! – Josh

0

你試圖實現的是JavaScript中的某種面向對象的解決方案。看一下at this blog post,它詳細描述了它,並且給出了一個很好的例子。 :-)

+0

埃裏克我會讀一讀謝謝你的幫助:) – Josh

0

可以使用Obj.call(this,args)調用父構造函數。代碼還應該保留level1的原型,level1.prototype = new level()的賦值,因爲這將創建兩個對象之間的繼承關係。

function level(config) { 
    if(config){ 
     this.someProperty = config.prop; 
     alert("Level constructor"); 
     alert("Level property " + this.someProperty); 
    } 
} 

function level1(config) { 
    level.call(this, config); 
    this.someProperty2 = config.prop2; 
    alert("Level1 Construtor"); 
    alert("Leve1 property " + this.someProperty2); 
    alert("Level1 using prop from level " + this.someProperty); 
} 

level1.prototype = new level(); 

var myLevel = new level1({ 
    prop: "Test prop", 
    prop2: "Test prop2" 
}); 

工作實例http://jsfiddle.net/kz2Xc/1/

+0

嗨凱文, 所以在這個例子中,'level'構造函數在運行時不會做任何事情,因爲它的內容在條件if語句中? 像這樣做或使用Object.create更有利嗎?兩者都似乎建立繼承而不執行構造函數代碼。 Object.create對我來說似乎更有效率? - 但我不知道。 感謝您的幫助! – Josh

+0

@Josh用johns方法去吧,我更喜歡它 –

+0

當然,這對我來說似乎更簡單。感謝您的快速幫助 – Josh

0

用戶JonathanLonowski已經回答了您關於如何避免在設置inheritanc時調用構造的問題。但我也讀過你的問題是關於inhertance如何在JavaScript中工作的一般問題。所以這裏是我試圖解釋這個話題:

當談到繼承,你基本上想要做的是增強原型鏈。

那麼,它的原型鏈是什麼?

當您請求一個對象的屬性,即obj.prop時,JavaScript首先檢查對象obj是否具有這樣的屬性。如果不是,它會檢查該對象的原型是否具有這樣的屬性。如果不是,它會檢查原型的原型是否具有這樣的屬性,等等。

當你寫obj = new B()創建一個構造函數一個新的對象,然後原型鏈如下所示:

obj -> B.prototype -> Object -> null 

繼承如何與原型鏈

如果你希望你的B對象從類型A的對象繼承,你想你原型鏈看起來像這樣:

obj -> B.prototype -> A.prototype -> Object -> null 

爲了達到這個目的,您需要在B.prototype之後「打破」原型鏈,然後插入A的完整原型鏈。換句話說,你想設置B.prototype指向A.prototype

你可以做到這一點,因爲你以前那樣:

B.prototype = new A(); 

現在爲什麼做這項工作?通過new A()創建的對象具有以下原型鏈:

objA -> B.prototype -> Object -> null 

如果覆蓋B.prototype與該對象,B類型的對象的原型鏈是這樣的:

objB -> objA -> A.prototype -> Object -> null 

正如你看到的, 有用。通過簡單地覆蓋B.prototype,您只會失去一些屬性,如constructor屬性。因此,如果您嘗試獲取B類型的constructorobjB.constructor的對象,它首先在對象本身中查找並找不到它,然後查找objA並且找不到它,然後查找A.prototype並查找A,這是錯誤的。雖然你不需要constructor財產往往也算是很好的做法,覆蓋B.prototype之後再進行設置:

B.prototype = new A(); 
B.prototype.constructor = B; 

現在,你的方式只是一種實現原型鏈的鏈接。喬納森·洛諾夫斯基的解決方案是另一個,也是更好的解決方案,因爲它不稱爲函數A。它創建具有相同的原型鏈一個空對象作爲A類型的對象:

(empty object) -> A.prototype -> Object -> null 

另一種解決方案將是不越權B.prototype但修改它以簡單地指向A.prototype代替Object。並非所有的瀏覽器都支持這一點,但在一些你可以通過設置__proto__屬性實現這一點:

B.prototype.__proto__ = A.prototype; 

這將導致以下原型鏈:

obj -> B.prototype -> A.prototype -> Object -> null 

請注意,我simplyfied在這裏在那裏,但我認爲這應該讓你知道它是如何工作的。要了解的基本原理是原型。從技術上講,現在只有一個真實的原型屬性,即每個對象都具有屬性[[prototype]]。您無法直接通過JavaScript訪問它,但您有.prototype.__proto__可以在特定條件下對其進行設置和操作。

+0

basilikum我讀過你在這裏寫的東西,這很有道理,現在我真的需要去把它放入應用程序中,以便它沉入其中。感謝堆徹底和清晰的解釋! – Josh