2013-01-14 23 views
1

我試圖以最簡單的方式實現繼承。我知道JS繼承是基於原型的,但由於我更精通OO基於類的語言,我有點偏向於將「類」邏輯封裝在「構造函數」函數中。此外,我試圖避免在原型對象中定義新成員,因爲代碼應該放在「類」功能之外。下面是我的嘗試:繼承:如何在overriden方法內模擬super.method

function Car(color, year, plate) { 
     this.color = color; 
     this.year = year; 
     this.plate = plate; 
     this.hasFuel = true; 
     this.fuel = 100;  

     this.run = function(km) { 
      this.fuel = this.fuel - km*this.getFuelConsumptionRate(); 
      if(this.fuel < 0){ 
       this.fuel = 0; 
      } 
      if(this.fuel == 0){ 
       this.hasFuel = false; 
      } 
     }; 

     this.getFuelConsumptionRate = function(){ 
      return 4.2; 
     }; 
    } 

    function EfficientCar(color, year, plate, weight){ 
     //Emulating a super call 
     Car.call(this, color, year, plate); 

     this.weight = weight; 

     //Overriden method 
     this.getFuelConsumptionRate = function(){ 
      return 2.2; 
     }; 
    } 
    //Inheritance 
    //(I don't like this out of the method, but it is needed for the thing to work) 
    EfficientCar.prototype = Car; 
    EfficientCar.prototype.constructor = EfficientCar; 

此代碼按預期工作:高效的汽車有呼籲運行在相同數量的公里後留下的更多的燃料。但是現在我想在被覆蓋的子版本中使用函數的父版本。這樣的事情:

function EfficientCar(color, year, plate, weight){ 
     //Emulating a super call 
     Car.call(this, color, year, plate); 

     this.weight = weight; 

     this.getFuelConsumptionRate = function(){ 
      return super.getFuelConsumptionRate()/2; //If only I could do this... 
     }; 
    } 

是否有類似於類的方式實現這種方式?我想有CarEfficientCar ,對不起,裏面的功能幾乎一切。

+0

不認爲這是最好的初步實踐,但'返回Car.prototype.getFuelConsumptionRate()/ 2'應該工作 – VeXii

+0

@VeXii不,瀏覽器說'Car.prototype.getFuelConsumptionRate'不是一個函數。 –

+0

這個相關的問題(不是重複的)可能很有用:http:// stackoverflow。com/questions/13359363/javascript-when-to-define-functions-inside-constructor-and-when-to-use-prototyp –

回答

1

如果你想打電話在「superclasse」中定義的函數,你應該正確使用原型,在界定上原型的功能,而不是實例:

Car.prototype.getFuelConsumptionRate = function() { 
return 4.2; 
} 

EfficientCar.prototype = new Car(); 

然後繼承,你將能夠調用父類的函數:

EfficientCar.prototype.getFuelConsumptionRate = function(){ 
    var superfun = this.constructor.prototype.constructor.prototype.getFuelConsumptionRate; 
    return superfun.call(this)/2; 
}; 

Complete demonstration(打開控制檯)

它你把它實踐調用超級函數(在我看來是一個糟糕的函數),那麼你可以建立一個小方法嵌入並縮短獲取方法。

如果你確切地知道繼承的目標水平,這當然更容易,因爲你可以簡單地用

var superfun = EfficientCar.prototype.getFuelConsumptionRate; 

注意,JavaScript是不完全不是同一取代

var superfun = this.constructor.prototype.constructor.prototype.getFuelConsumptionRate; 

你看起來更習慣於其他語言。嘗試應用外來模式通常導致更詳細,更不靈活和更少維護的程序。

+0

感謝您的回答。這工作。仍然存在一些我無法理解的東西:在Car類中,run函數調用this.getFuelConsumptionRate,但是該函數並沒有在Car中定義,而是在Car.prototype中定義。爲什麼它不會拋出錯誤? –

+0

因爲在JavaScript函數中是「一等公民」。你可以使用[call](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/call)或[apply](https: //developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/apply)。你並沒有真正在一個對象上定義一個函數:你定義一個函數,然後把它賦值爲對象屬性的值。 –

+0

我的意思是爲什麼在'run'函數中我們可以使用'this.getFuelConsumptionRate'而不是'this.prototype.getFuelConsumptionRate'。我不記得如果一個對象沒有成員,它就會被轉發到原型。 –

2

如果你想在JavaScript中使用繼承我會建議你使用約翰Resig的這個小寶石:

http://ejohn.org/blog/simple-javascript-inheritance/

例如,從博客:

var Person = Class.extend({ 
    init: function(isDancing){ 
    this.dancing = isDancing; 
    }, 
    dance: function(){ 
    return this.dancing; 
    } 
}); 

var Ninja = Person.extend({ 
    init: function(){ 
    this._super(false); 
    }, 
    dance: function(){ 
    // Call the inherited version of dance() 
    return this._super(); 
    }, 
    swingSword: function(){ 
    return true; 
    } 
}); 

var p = new Person(true); 
p.dance(); // => true 

var n = new Ninja(); 
n.dance(); // => false 
n.swingSword(); // => true 

// Should all be true 
p instanceof Person && p instanceof Class && 
n instanceof Ninja && n instanceof Person && n instanceof Class 
+0

我已經閱讀過它。目前再次閱讀。 –

0

我不喜歡這樣,使用的Object.create()時,不支持的功能它一個墊片。

var Car = function() { 
    // code 
}; 

Car.prototype.getFuelConsumptionRate = function() { 
    // code 
}; 


var EfficientCar = function() { 
    Car.call(this); 
}; 

EfficientCar.prototype = Object.create(Car.prototype); 

EfficientCar.prototype.getFuelConsumptionRate = function() { 
    var result = Car.prototype.getFuelConsumptionRate.call(this) 
    // code 
};