2014-02-24 233 views
2

我想弄清楚如何使用任意數量的參數(從某些其他函數調用傳遞參數)調用構造函數。如何將任意參數傳遞給javascript構造函數

我在JavaScript中有一組基和派生對象。其中一個基礎對象的方法稱爲makeNew(),它的工作是創建一個與它所調用的對象類型相同的新對象,並處理與新對象上的普通構造函數相同的所有參數。此makeNew()方法的要點在於,還有其他方法需要創建與當前對象相同類型的新對象,但他們不知道是什麼類型,因爲它可能是從基類繼承的類型。請注意,我不想整個克隆當前對象,而是需要一個相同類型的新對象,但使用不同的初始參數初始化爲構造函數。

makeNew()簡單的版本是這樣的:

set.prototype.makeNew = function() { 
    return new this.constructor(); 
} 

這適用於創建同一類型,則當前的空對象,因爲如果它是一個繼承的對象類型,然後this.constructor將是繼承的構造和它會做出正確的對象類型。

但是,當我想傳遞任意參數給構造函數,所以正常的構造函數參數可以傳遞給makeNew(),我無法弄清楚如何做到這一點。我嘗試這樣做:

set.prototype.makeNew = function() { 
    return new this.constructor.apply(this, arguments); 
} 

但是,該代碼給了我這個錯誤在Chrome:

Error: function apply() { [native code] } is not a constructor 

不知道如何對任意參數傳遞給構造函數?

+0

我不明白是什麼第一個版本的問題。 '返回新this.constructor(參數);'應該工作。 – TastySpaceApple

+1

@TastySpaceApple - 將單個參數傳遞給構造函數,該構造函數是一個類似數組的對象,而不是構造函數期望其多個參數如何傳遞。 – jfriend00

+0

@cookiemonster - 我將不得不在你引用的帖子中試用這種技術。這是一個有趣的黑客。 – jfriend00

回答

3

我看到它的唯一方法是你必須創建一個方法來將數組分散到參數中。

例如,此方法首先創建新對象,然後使用apply傳播數組。

Function.prototype.construct = function(argArray) { 
    var constr = this; 
    var inst = Object.create(constr.prototype); //creates a new empty object 
    constr.apply(inst, argArray); // triggers the constructor (as a function) 
    return inst; 
}; 

那麼你可以使用

return set.construct(array) 

http://www.2ality.com/2011/08/spreading.html

注更多(更多):的Object.create現在可能會在老瀏覽器中運行。使用https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create

+0

這是做到這一點的方法。還有一些其他的方法,但這是最乾淨的。 –

+0

Thx。我以前見過類似的東西。我希望不要依賴'Object.create()',所以老的IE 8仍然可以運行我的代碼。 – jfriend00

+0

@ jfriend00:給它一點點吧。 –

1

如果您可以更改構造函數,這種方式對我來說似乎合法,它依賴於javascript中構造函數,對象和函數之間的微妙差異。現在

function set(arg1, arg2, arg3){ 
    // entered the constructor, `this` = new object (like using Object.create) 
    if(arg1 instanceof Array){ //if arg1 is an array 
     this.constructor.apply(this, arg1); //use apply to spread it 
     // apply now refers to the constructor as a function 
     // notice the reference to `this.constructor`. 
     // This is because `this` no longer refers to the function, 
     // but to the newly created object. 
    }else{ 
     // the actual function. 
     console.log(arg2); 
    } 
} 
new set([1,2,3]) 

它給你找出如何在原型繼承這項工作......他們這樣,我看到它,你必須在每類中複製該代碼。或者讓它繼承:

function set(arg1, arg2, arg3){ 
    if(set.prototype.initCheck.call(this, arg1)){ //this will have to be copied to every inherited class... 
     ///the actual constructor 
    } 
} 
set.prototype.initCheck = function(arg1){ 
    if(arg1 instanceof Array){ //if arg1 is an array 
     this.constructor.apply(this, arg1); //use apply to spread it 
     return false; 
    } 
    return true; 
} 
new set([1,2,3]) 
+1

其實你讓我想起你可能選擇的原因之一不在構造函數本身中放置初始化代碼,而是在構造函數調用的'init()'方法中。這樣你就不必用參數調用構造函數。您可以調用一個空構造函數,獲得一個新的空對象,然後在新對象上調用'this.init.apply(this,arguments)',以獲得與使用參數調用構造函數完全相同的結果。這是一個慣例,但遵循這個慣例解決了這個問題(如果你控制了所有涉及的對象)。 – jfriend00

+0

嗯,這是個好主意。 – TastySpaceApple

0

回答我自己的問題。各種討論導致我對此有幾種可能的解決方案。

如果您控制所有涉及的對象,您可以將所有活動代碼從構造函數中取出並放入.init()方法中並遵循該設計模式。然後,你可以這樣做:

function set() { 
    this.init.apply(arguments); 
} 

set.prototype.init = function() { 
    // process all constructor arguments here 
} 

set.prototype.makeNew = function() { 
    // create object of the same type as what we are 
    // even if it's a derived object type 
    var newSet = new this.constructor() 

    // apply any constructor arguments 
    newSet.init.apply(newSet, arguments); 

    return newSet; 
} 

所有派生類也必須遵循同樣的.init()設計模式,包括他們是否添加或處理的任何構造函數參數本身不僅僅是讓基類處理的構造函數調用基類參數。


事實上,在情況下,一個空的構造並沒有做太多,並沒有任何問題,被稱爲兩次,你甚至可以做到這一點:

function set() { 
    // do whatever object initialization from arguments 
    // that the object wants to do 
} 

set.prototype.makeNew = function() { 
    // create object of the same type as what we are 
    // even if it's a derived object type 
    // first time called without any constructor arguments 
    var newSet = new this.constructor(); 

    if (arguments.length) { 
     // apply any constructor arguments 
     // by simply calling the constructor again without "new" 
     // and this time passing it the object we already made 
     // and the arguments we have 
     this.constructor.apply(newSet, arguments); 
    } 

    return newSet; 
} 
+0

對於沒有任何不良副作用的構造函數來說,沒有參數被調用是特定的,但在這種情況下它應該可以正常工作。 –

+0

@cookiemonster - 是的,你是對的。我還發現一個更簡單的方法,如果構造函數不介意先被調用兩次,沒有參數,然後再與參數一起調用。 – jfriend00

相關問題