2012-10-24 69 views
3

我經常發現自己需要爲了各種目的在對象上包裝函數。有沒有一種優雅的方式來保留包裝函數上原始函數的length屬性?包裝函數的設置長度

例如:

var x = { 
    a: function(arg1, arg2) { /* do something */ } 
}; 

function wrap(obj) { 
    var original = obj.a; 
    obj.a = function wrapper() { 
     console.log('a called'); 
     original.apply(this, arguments); 
    }; 
} 

x.a.length; // => 2 
wrap(x); 
x.a.length; // => 0 

我會想做什麼:

var x = { 
    a: function(arg1, arg2) { /* do something */ } 
}; 

function wrap(obj) { 
    var original = obj.a; 
    obj.a = function wrapper() { 
     console.log('a called'); 
     original.apply(this, arguments); 
    }; 
    obj.a.length = original.length; 
} 

x.a.length; // => 2 
wrap(x); 
x.a.length; // => 2 (actual still 0) 

然而,這不起作用,因爲length不可寫。

我現在唯一能提出的解決方案是(1)動態生成函數作爲字符串並且(2)具有不同長度的代理函數的巨陣列並選擇代理功能對應於正確的長度。這對我來說似乎不是一個優雅的解決方案,似乎是一個合理的請求,可以用任意指定函數中的每個參數來創建一個具有任意length而沒有的函數。

好像bind是能夠在內部做到這一點:

function a(b, c) { } 
a.bind(null).length; // => 2 

這將創建一個包裝函數與原來的長度!這正是我想要自己做的。

有沒有其他辦法?

+0

是否_have_要長?你可以將它複製到另一個屬性 - 甚至可以將函數添加到函數原型以獲取長度或複製的變量,以便函數返回包裝和解包函數的長度? – sje397

+0

只是想知道,但實際_use_是一個函數的'.length'屬性? – Alnitak

+0

是的,它必須是'長度'。 @Alnitak,我從來沒有使用它,但作爲一個框架開發人員,我想創建一個模仿原始函數的通用包裝器,包括'length'屬性。它是ES規範的一部分,我希望我的框架支持它,而不管* I *是否有用。別人可能會。 –

回答

1

我喜歡的eval(... )方法,因爲它很簡單。

function wrap(obj) { 
    var f = obj.fun.toString(); 
    f = f.replace("{", "{ alert('wrapper'); "); 
    obj.fun = eval('['+f+']')[0]; 
} 

你可以擴展這種有包裝表示包裝功能,並獲得更豐富的與字符串操作把它們結合在一起的第二個參數。

如果你的目標是包裝的透明度,那麼只要利用編程語言的動態功能即可。


如果你願意做你的JavaScript文件額外的處理,你可以有你的熱補丁/包裝內置的。

var x = { 
    a: function(arg1, arg2) { 
     (x._a || (function(){}))(); 
     ... do actual function stuff ... 
    } 
} 
function wrap(obj) { 
    obj._a = function() { 
     console.log("ok"); 
    } 
} 
+0

+1。你可能是對的,'eval'在這裏可能並不是一個非常糟糕的選擇,謝謝你幫我考慮一下,我會留下這個問題。有一段時間,看看是否有人提出任何其他的,但到目前爲止,這是唯一真正的答案。謝謝 –

+0

@Nathan Wall - 實現一個版本的「包裝」功能說0-9參數也不是很差,微軟使用非常類似的方法來創建它.Net框架中的eric Tuple類。 –

0

如果你需要得到的包裝和功能展開的長度以同樣的方式,而是能夠不使用length屬性,這樣的事情可能會有所幫助:

Function.prototype.mylengthf = function() { 
    return this.mylength | this.length; 
}; 

var x = { 
    a: function(arg1, arg2) { /* do something */ }, 
    b: function(arg1, arg2, arg3) { /* do something else */ } 
}; 

function wrap(obj) { 
    var original = obj.a; 
    obj.a = function wrapper() { 
     console.log('a called'); 
     original.apply(this, arguments); 
    }; 
    obj.a.mylength = original.length; 
} 

log(x.a.length); // => 2 
wrap(x); 
log(x.a.length); // => 0 
log(x.a.mylengthf()); // => 2 
log(x.b.mylengthf()); // => 3 
​ 
+0

這不適合我的使用,我編寫框架,低級抽象,填充和補丁,我需要我的代碼可以放到任何人的項目中,而不必教他們使用'mylength'而不是'或者強迫他們重構現有的代碼 –