2009-10-11 16 views
8

Załóżmy, że dostaję anonimową funkcję, która wymaga działania w kontekście, ale różni się od tego, czy jest powiązana z "oknem", czy z nieznanym obiektem.Jak uzyskać "to" (zakres) funkcji anonimowej Javascript?

Jak uzyskać odwołanie do obiektu, z którego wywoływana jest funkcja anonimowa?

EDIT, niektóre kod:

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); 

Można zasadnie zapytać, dlaczego do cholery chcesz zrobić coś takiego. Cóż, najpierw chciałem rozpakować argumenty przekazane jako tablica. Podobnie jak w Pythonie "*" operator robi:

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

I wykopali w SO i znalazł post mówiąc używać "apply()":

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

Ciekawe ponieważ zamierza wykorzystać obecny " to "jeśli w obiekcie i" okno ", jeśli nie.

Ale myślę, że jest to problem:

czy „bar()” jest sama w obiekcie, po czym „to” będzie odnosić się do „bar()” pojemnika, dla nich to nie będzie działać.

BTW, Chciałbym nie przekazywać zakresu jako parametru.

Mogę oczywiście połączyć argumenty i funkcję jako ciąg, a następnie użyć eval, ale chciałbym użyć tego tylko wtedy, gdy nie mogę znaleźć czegoś czystszego.

Oczywiście, jeśli to tylko możliwe (po wszystkim, to może być), to zrobię:

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

EDIT 2: pełny scenariusz, co postulowano w komentarzach.

Używam qunit do wykonywania testów jednostkowych w Javascript. To jest fajne, ale brakuje mi sposobu sprawdzenia, czy coś podnosi wyjątek.

Najbardziej podstawowe badanie odbywa się w ten sposób:

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

Chodzi o to, aby coś takiego:

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 ]); 
    } 
}; 

Gdybym mógł pozbyć się eval, to byłoby świetnie. I dlaczego nie chcę używać zakresu jako parametru? Ponieważ możesz chcieć zainicjować pętlę na kontenerze odwołującym się do 20 funkcji z różnymi zakresami i przetestować je wszystkie w pętli zamiast ręcznie zapisywać rzeczy.

+2

Czy możesz podać przykład kodu? Mam pewne trudności w zrozumieniu tego, czego naprawdę chcesz. –

+0

Tak, nie jestem pewien, czego szukasz. Podaj próbkę kodu. – SolutionYogi

+0

Masz rację, gotowe. –

Odpowiedz

6

e-satis,

Jedynym sposobem na to jest użycie połączenia lub zastosować metodę, aby ustawić poprawny 'kontekst'.

Aby rozwiązać problem, zmodyfikuj funkcję paska, aby zaakceptować funkcję wywołania zwrotnego, a także zakres zastosowania tej funkcji zwrotnej.

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

bar(ObjectFromOtherLibIAmNotSupposedToknowAbout.foo, ObjectFromOtherLibIAmNotSupposedToknowAbout); 

Alternatywnie można użyć metody "wiązania".

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

Teraz można zostawić funkcję bar nietknięty i modyfikować kod wywołujący wyglądać,

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

EDIT:

Jak zauważono w komentarzu, to odpowiedzialność kod wywołujący, aby przekazać poprawną funkcję zwrotną. Twoja funkcja "paska" nie może określić, jakiego zakresu użyć, kropka.

Weź to na przykład

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

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

Jak masz zamiar dowiedzieć się, jaki powinien być zakres? Nie ma już nic do "parsowania" i nie ma możliwości zmodyfikowania funkcji "paska", aby to działało.

+1

Cześć, dziękuję, ale to jest hakowanie trochę przedłużenia dla ramowego testu jednostkowego, nie mam zakresu testowanej funkcji pod ręką (i nie powinienem mieć). –

+0

Czy odpowiadasz za pisanie tej metody, czy nie? W JS funkcje nie są dołączane do obiektów, a mechanizm JS decyduje o tym, którego kontekstu użyć, chyba że zostanie to wyraźnie określone za pomocą wywołania/zastosowania. – SolutionYogi

+0

Jestem, ale nie mogę poprosić o napisanie 1000 testów w sposób (składnia qunit), pewną sygnaturę i zrobienie wyjątku dla małego hackowania. Przerwałoby to spójność API, nie było tego warte. Nic wielkiego, to pytanie nie jest kwestią życia ani śmierci :-) –

Powiązane problemy