2013-09-22 118 views
1

雖然我的框架內工作的想法來到我的腦海裏。我使用$elect(id).hide()來選擇一個元素並用它做東西。沒有錯。但是,如果我想改變選擇,用別的東西嗎?我不得不精文檔中的每個$elect,手動替換所有的人。那很無聊。所以我在想,如果這樣的事情是可能的:動態函數/對象名稱

var selector = $elect; // or anything else 

function [selector](id) { 
    if (!(this instanceof [selector])) { 
     return new [selector](id); 
    } 
    this.elm = document.getElementById(id); 
} 

[selector].prototype = { 
    hide: function() { this.elm.style.display = 'none'; return this; } 
} 

window.[selector] = [selector]; 

動態地改變功能/對象名稱。這會節省很多時間。如果有其他人使用該框架,他們可以定義他們自己的選擇器。這不是很好嗎?有任何想法嗎?

+0

所以你想分配屬性到一個原型中,但是能夠動態地選擇哪個對象的原型來將它們添加到這些行中? –

+0

就是這樣的。那麼,我也應該能夠改變構造函數的名字。使用'selector'變量。 – akinuri

回答

0

這個怎麼樣簡單的通用模式(我的最愛)?

(function(){         //IIF constructor builder 
    (this[arguments[0]]= function(/*args*/){ //The constructor 
     /*constructor payload code*/ 
    }).prototype= {       //Methods & Properties to inherit: 
     method_1: function(){ /*your code*/ } //method 1 
    , method_2: function(){ /*your code*/ } //method 2 
    , property_1: /*your code*/    //property 1 
    , property_2: /*your code*/    //property 2 
    }; 
})(/*constructor identifier*/); 

this將引用運行此構建函數的上下文。所以,如果構造函數生成器對window運行,那麼window將有全球功能$elect。所以你也可以在你的模塊化系統中使用這種模式。


更新:
你問 instanceof(和你提供的代碼來看,你需要它,人們可以調用構造函數時省略 new)。 這可能會讓事情變得更棘手。

對我個人而言,'users'!=='coders'和'coders'(誰編寫代碼(使用x庫)供用戶使用)應該知道何時使用new
雖然它可能是有用的,在開發過程中throw new/console.log/alert錯誤,應該在最後的(最小化/優化)的生產代碼不需要這個(除非你的觀點是,你有很多的new陳述,可以省略,所以你的代碼可以進一步縮小)。

首先,你必須決定是否要爲
執行速度和使用的new優化(代碼通常運行?):

if(/*called with new*/){ 
    /*constructor payload code*/ 
} else { 
    /*error code*/ 
} 

或最小的文件大小是缺乏new在執行速度的代價(代碼運行只是一對夫婦的次):

if(!(/*called with new*/)){ /*error code*/ } 
/*constructor payload code*/ 

注意的是最後的選擇也可能是更實際的註釋掉/刪除生產代碼,如果您打算要求使用new,提供最快的執行速度。

/*called with new*/可以用this instanceof arguments.callee雖然arguments.callee是一個很好的通用的解決方案(因爲沒有被硬編碼/命名),它會拋出異常來代替,如果你'use strict'; - 模式,因爲它現在已經過時(出於某種原因)在favor of named function expressions(根據約翰Resig的,一個也使用在未來expression this function)。

MDN specifies that a function name can be used only within the function's body,所以嚴格的模式,我們可以(在下面的例子C)命名我們(以前匿名)功能
和檢查(而不是this instanceof arguments.calleethis instanceof C

(function(){         //IIF constructor builder 
    (this[arguments[0]]= function C(id){  //The constructor 
     if(!(this instanceof C)){ /*error code*/ } //Catch ID-10-T Error 
     /*constructor payload code*/ 
    }).prototype= {       //Methods & Properties to inherit: 
     method_1: function(){ /*your code*/ } //method 1 
    , method_2: function(){ /*your code*/ } //method 2 
    , property_1: /*your code*/    //property 1 
    , property_2: /*your code*/    //property 2 
    }; 
})('$elect'); 

如果/*error code*/只是阻止無聲錯誤由:
alert/console.log/throw new Error('Error: forgot new')
然後直到現在這種模式(既嚴格和非ST rict變體)是非常通用的。

如果您想通過返回適當的新對象(除了現在對編碼器的可選警告)來「修復」調用,那麼必須考慮傳遞給構造函數的參數(如果有的話)。
因此,對於那些不要求參數的構造函數,你/*error code*/應該包含:
return new arguments.callee();非嚴格或
return new C();對於希望嚴格
構造函數(可選)命名參數,您/*error code*/應該讓它們硬編碼,如:
return new arguments.callee(arg_1, arg_2 /*,etc..*/);用於非嚴格或
return new C(arg_1, arg_2 /*,etc..*/);嚴格

作爲例子:

(function(){         //IIF constructor builder 
    (this[arguments[0]]= function C(id){  //The constructor 
     if(!(this instanceof C)) return new C(id); //Fix ID-10-T Error 
     this.elm= document.getElementById(id); 
    }).prototype= {       //Methods & Properties to inherit: 
     show: function(){      //Method show 
     this.elm.style.display= ''; 
     } 
    , hide: function(){      //Method hide 
     this.elm.style.display= 'none'; 
     } 
    , toggle: function(){      //Method toggle 
     this[this.elm.style.display ? 'show' : 'hide'](); 
     } 
    }; 
})('$elect'); 

我目前沒有意識到一個簡單而優雅的方式來傳遞任何(對於firefox最多256)非硬編碼未知(預期/可選/命名)參數(缺少一個單一數組/對象作爲第一個參數)。問題是,arguments是一個數組(類似)的對象,所以不能簡單地通過它像return new C(arguments);
.apply()到一個人可能會想到的救援,因爲它接受一個參數數組作爲第二個參數(不像.call()需要逗號 - 但是可惜:newapply/call不能一起使用1,2 ...(有人,請留下評論,如果你知道一個優雅的解決方案,適合這種模式,謝謝)

最後一個小變化(和可能的應用)到上述模式。主要的區別是,這種模式會返回一個構造函數(這樣你就可以簡單地指明引用它的變量)(而不是直接設置構造上面的圖案):

var myLibrary= { 
    $elect: (function(C){ 
       (C= function(id){ 
       if(!(this instanceof C)) return new C(id);   
       this.elm= document.getElementById(id);    
       }).prototype= { 
       addBorder: function(col){        
        this.elm.style.border='1px solid '+col;   
       }             
       , delBorder: function(){        
        this.elm.style.border='';      
       }  
       }; return C;            
      })() 
, var_foo: 'foo' 
, var_bar: 'bar' 
}; 

Example fiddle here

希望這會有所幫助!

+0

另一個很好的解決方案,但不是傳入一個字符串,而是傳入對象。例如。 '(function(obj){obj = whatever; obj.prototype = whatever;})($ elect);' –

+0

@GitaarLAB你能用jsfiddle中的單一方法顯示你的代碼的一個工作示例嗎? – akinuri

+0

@akinuri:完成,看到更新的答案。 @JaniHartikainen:爲什麼這樣更好,並且..,我不能讓你的例子工作'(function(obj){obj = whatever; obj.prototype = whatever;})($ elect);'(當前置'var $ elect;'或'var $ elect = {};')。請您**請詳細說明**(也許張貼您的方式作爲答案)?這兩種模式在範圍/關閉鏈上是否存在差異? – GitaarLAB