2009-10-11 85 views
8

比方說,我得到一個匿名函數的需要作用於它的上下文,但無論是綁定到「窗口」或不明物體是不同的。如何獲得Javascript匿名函數的「this」(範圍)?

我如何獲得一個匿名函數被調用的對象的引用?

編輯,一些代碼:

var ObjectFromOtherLibIAmNotSupposedToknowAbout = { 
    foo : function() { 
     // do something on "this" 
    } 
} 

var function bar(callback) { 
    // here I want to get a reference to 
    // ObjectFromOtherLibIAmNotSupposedToknowAbout 
    // if ObjectFromOtherLibIAmNotSupposedToknowAbout.foo is passed 
    // as callback 
} 

bar(ObjectFromOtherLibIAmNotSupposedToknowAbout.foo); 

你可能合法地要求,爲什麼赫克你會喜歡做這樣的事情。那麼,我首先想解開作爲數組傳遞的參數。就像Python的「*」操作不:

>>> args = [1,2,3] 
>>> def foo(a,b,c) : 
     print a,b,c 
>>> foo(*args) 
1 2 3 

我在SO挖,發現了post告訴使用「申請()」:

function bar(callback, args){ 
    this[callback].apply(this, args); 
} 

有趣,因爲它會使用當前「這個「如果在一個對象中,而」窗口「如果不是。

但我覺得有一個問題:

如果「欄()」本身就是一個對象,那麼「這」指的是「扎()」的容器,爲此它不會工作。

順便說一句,我不想通過範圍作爲參數

我當然可以級聯這些參數和函數作爲一個字符串,然後使用eval,但我想用這隻如果我不能找到更清潔。

當然,如果它只是不可能的(畢竟,它可能是),那麼我會做:

function foo(func, args) 
{ 
    eval("func("+args.join(", ")+");"); 
} 

編輯2:全場景,如問意見。

我使用qunit在JavaScript進行單元測試。這很酷,但我想念一種方法來檢查是否引發異常。

最基本的測試是這樣:

/** 
* Asserts true. 
* @example ok($("a").size() > 5, "There must be at least 5 anchors"); 
*/ 
function ok(a, msg) { 
    _config.Test.push([ !!a, msg ]); 
} 

的想法是讓這樣的:

jqUnit.prototype.error = function(func, args, msg) 
{ 
    try 
    { 
     eval("func("+args.join(", ")+");"); 
     config.Test.push([ false, msg + " expected : this call should have raised an Exception" ]); 
    } catch(ex) 
    { 
     _config.Test.push([ true, msg ]); 
    } 
}; 

如果我能擺脫的EVAL,這將是巨大的。爲什麼我不想將範圍用作參數?因爲您可能想要循環引用具有不同範圍的20個函數的容器,並在循環中測試它們,而不是手動編寫這些東西。

+2

你能提供一些代碼示例嗎?我理解你真正想要的東西有些困難。 – 2009-10-11 14:13:40

+0

是的,我不知道你在找什麼。請提供一些代碼示例。 – SolutionYogi 2009-10-11 14:15:09

+0

你說得對,做完了。 – 2009-10-11 14:22:56

回答

6

e-satis,

唯一的方法是使用call或apply方法來設置正確的「上下文」。

解決您的問題,修改酒吧函數接受回調函數以及範圍,適用於回調函數。

function bar(callback, scope) 
{ 
    callback.apply(scope); 
} 

bar(ObjectFromOtherLibIAmNotSupposedToknowAbout.foo, ObjectFromOtherLibIAmNotSupposedToknowAbout); 

或者,您可以使用'bind'方法。

Function.prototype.bind = function(context) { 
    var fun = this; 
    return function(){ 
    return fun.apply(context, arguments); 
    }; 
}; 

現在,您可以留下您的酒吧功能不變,並修改調用代碼的樣子,

bar(ObjectFromOtherLibIAmNotSupposedToknowAbout.foo.bind(ObjectFromOtherLibIAmNotSupposedToknowAbout)); 

編輯:

正如我在評論指出,這是責任調用代碼傳遞正確的回調函數。你的'bar'函數不能確定使用哪個範圍,句點。

拿這個爲例,

var LibObject = { foo: function() { //use this inside method } }; 

var fooFunction = LibOjbect.foo; 
bar(fooFunction); 

你打算怎麼弄清楚應該是什麼範圍?現在沒有什麼東西可以「解析」了,而且你也無法修改你的'bar'函數來完成這項工作。

+1

你好,謝謝,但它是爲單元測試框架黑客擴展一點,我沒有測試函數的範圍(不應該有)。 – 2009-10-11 14:46:50

+0

您是否負責編寫該欄方法調用?在JS中,函數不會附加到對象,JS引擎將決定使用什麼上下文,除非您使用call/apply明確指定它。 – SolutionYogi 2009-10-11 14:50:16

+0

我是,但是我不能要求1000個測試以某種方式寫(qunit語法),某個簽名,並且爲了方便起見,我編寫了一些小黑客的例外。它會破壞API的一致性,這不值得。沒什麼大不了的,這個問題不是生死攸關的問題:-) – 2009-10-11 14:54:46