2012-12-04 51 views
3

這是我第一次OOP刺,所以請多多包涵:如何傳遞一個對象的方法陣列的方法在JavaScript中

(function(){ 

    var Ship = function(){ 
    this.passengers = []; 
    this.hasAliens = function() { 
     return this.passengers.some(function(passenger){ 
     return passenger.isAlien() 
     }); 
    }   
    }; 

    var Passenger = function(){}; 
    Passenger.prototype.isAlien = function(){ 
    return this instanceof Alien; 
    }; 
    Passenger.prototype.board = function(ship) { 
    ship.passengers.push(this) 
    } 

    var Alien = function() { Passenger.call(this); } 
    var Human = function() { Passenger.call(this); } 
    Alien.prototype = Object.create(Passenger.prototype); 
    Human.prototype = Object.create(Passenger.prototype); 
    Alien.prototype.constructor = Alien.constructor; 
    Human.prototype.constructor = Human.constructor; 

    var ship = new Ship(); 
    var john = new Human(); 
    var zorg = new Alien(); 

    //simple testing 
    john.board(ship); 
    console.log("Ship does not have aliens ", ship.hasAliens()===false); 
    zorg.board(ship); 
    console.log("Ship has aliens ", ship.hasAliens()===true); 

})(); 

這工作得很好。但是,我想知道如何通過Passenger.isAlien()方法來爲我節省那個討厭的嵌套匿名函數。我試圖做這樣的:

var Ship = function(){ 
    this.passengers = []; 
    this.hasAliens = function(){ 
     return this.passengers.some(Passenger.isAlien);   
    }; 
    }; 

但是,這給了我"undefined is not a function"

http://jsfiddle.net/WYyxY/

+2

你的代碼有一些缺陷。例如。 'Alien.prototype = Object.create(Passenger);'應該是'Alien.prototype = Object.create(Passenger.prototype);'而不是在'Passenger'構造函數中分配函數,你應該把它們分配給'Passenger .prototype'。關於你的問題:你得到的錯誤是因爲'isAlien'是構造函數的*實例*的屬性,而不是構造函數本身。沒有比使用匿名函數更簡潔的方法。 –

回答

1

正如我所說,isAlien爲原型的屬性,也就是的一個實例構造函數,而不是構造函數本身。 Passenger.isAlien的確是未定義的(在你的代碼中沒有任何地方是Passenger.isAlien = function....)。

有沒有一個更簡潔的方法來做到這一點。想想回傳給.some的回調是怎麼做的:它必須將數組的一個元素作爲參數,然後對其進行處理。在你的情況下,你想要執行該元素的方法。

調用一個方法並傳遞它應該作爲參數調用的對象的一種方法是使用.call[MDN]。不幸的是,與JavaScript中的所有函數一樣,您不能僅僅獲得對Passenger.prototype.isAlien.call的引用,因爲.call會丟失其上下文(它不知道它引用哪個函數)。您必須首先將其綁定到Passenger.prototype.isAlien

this.passengers.some(
    Passenger.prototype.isAlien.call.bind(Passenger.prototype.isAlien)  
); 

並且我個人發現它的可讀性不高。

堅持匿名功能,你的打算更清晰。或者,如果你願意,你可以讓另一個函數創建一個功能:

function callOn(funcName) { 
    return function(obj) { 
     return obj[funcName](); 
    }; 
} 

this.passengers.some(callOn('isAlien')); 
+0

感謝您的幫助,我重構了代碼。你怎麼看最高層級的'isAlien = function(passenger){...}'然後這將允許'return this.passengers.some(isAlien);'和'Passenger.prototype.isAlien = isAlien;' – Duopixel

+0

Passenger.prototype.isAlien = isAlien'不會像你期望的那樣工作。在這種情況下'isAlien'接受一個參數,所以'john.isAlien()'會通過一個錯誤,因爲'passenger'沒有在函數中定義。這基本上是一樣的問題,但反之亦然。你不得不打電話給'john.isAlien(john)',這也不是直截了當的。 –

+0

但是如果你做了類似「if(!alien)alien = this'的東西,那麼我可以提供上下文嗎? http://jsfiddle.net/WYyxY/2/。但我仍然不確定它更具可讀性。 – Duopixel

0

對於使用JavaScript實現面向對象編程,我強烈建議檢查出prototypeJS。你的代碼變得更可讀,並且它也支持繼承!

這是一個quick look

+0

謝謝indieman,我知道有些庫可以幫助我,但我想用直接的js來試用它。 – Duopixel

+0

繼承原生支持JavaScript。只是說'因爲你讓它聽起來好像沒有。 –

相關問題