2014-09-09 16 views
5

Mam daną funkcję, która pobiera, oprócz innych argumentów, dwa opcjonalne argumenty, które mogą być funkcjami. Oba muszą być opcjonalne, jeden będzie funkcją, a drugi będzie boolowskim lub funkcją zwracającą wartość logiczną.Sprawdź, czy funkcja JavaScript zwraca się bez jej wykonywania?

// Obj.func(variable, String[, Object][, Boolean||Function][, Function]); 
Obj.func = function(other, assorted, args, BoolOrFunc, SecondFunc) { 
    // execution 
}; 

Obj.func(
    [ 
     'some', 
     'data' 
    ], 
    'of varying types', 
    { 
     and: 'some optional arguments' 
    }, 
    function() { 
     if(some condition) { 
      return true; 
     } 
     return false; 
    }, 
    function() { 
     // do things without returning 
    } 
); 

To jest moje pragnienie, że obie funkcje (i kilka innych argumentów, jeśli ma to znaczenie) są opcjonalne, co oznacza, że ​​mam kod w funkcji, aby określić, które argumenty użytkownik zamierza wykorzystać.

Niestety, ponieważ obie mogą być funkcjami i mogą być określone bezpośrednio w wywołaniu funkcji, nie mogę po prostu użyć warunkowych typeof lub instanceof. Jednak od pierwszej funkcji, jeśli taka istnieje, zostanie zawsze zwróci wartość logiczną (a druga funkcja nie wróci w ogóle), jeden pomysł miałem byłoby sprawdzić jego wartość powrotu:

if(typeof BoolOrFunc === 'boolean' 
    || (typeof BoolOrFunc === 'function' && typeof BoolOrFunc() === 'boolean')) { 
    // BoolOrFunc is either a boolean or a function that returns a boolean. 
    // Handle it as the intended argument. 
} else { 
    // Otherwise, assume value passed as BoolOrFunc is actually SecondFunc, 
    // and BoolOrFunc is undefined. 
} 

ten działa w zasadzie; jednak uruchamianie typeof BoolOrFunc() wykonuje funkcję, która powoduje problem, jeśli funkcja nie tylko zwraca wartość boolowską: to znaczy, że funkcja przekazana jako BoolOrFunc jest faktycznie oznaczona jako SecondFunc. SecondFunc, w tym przypadku jest czymś w rodzaju funkcji wywołania zwrotnego i może wykonywać akcje, w tym modyfikacje DOM, których nie chcę wykonywać natychmiast.

Z tego powodu moje pytanie brzmi: Czy istnieje sposób, aby sprawdzić, czy funkcja zwraca bez wykonywania go?

Jedno miałem uważane było zadzwonić BoolOrFunc.toString(), a następnie wykonać wyszukiwanie wyrażenia dla wartości zwracanej, coś na wzór ...

if(typeof BoolOrFunc === 'boolean' 
    || (typeof BoolOrFunc === 'function' 
     && BoolOrFunc.toString().search(/return (true|false);/) !== -1)) { 
    // BoolOrFunc is either a boolean or contains a return string with a boolean. 
    // Handle it as the intended argument. 
} 

Zauważ, że powyższy kod może nie działać jak napisano: Nie zbudowałem dla niego przypadku testowego, ponieważ, cóż, wydaje się wyjątkowo nieskuteczne i potencjalnie niewiarygodne, i pomyślałem, że ktoś tutaj może mieć bardziej eleganckie rozwiązanie mojego dylematu. To powiedziawszy, doszedłem do wniosku, że uwzględnię to do celów dyskusji.

+1

Jako niepotwierdzonych marginesie, to jest dość blisko do powstrzymania problem (http://en.wikipedia.org/wiki/Halting_problem), który jest nierozstrzygalny nad Maszyna Turinga. :) – lexicore

+0

Heh, poruszysz dobry punkt. Prawdopodobnie oczekuję zbyt wiele od JS. : P – Meshaal

+0

Dla przypadku, który użytkownicy nazywają formularzem, który podaje wartość logiczną i funkcję, która zwraca wartość logiczną, można zamiast tego wymagać podania argumentów owiniętych w obiekcie, np. 'Obj.func (myvar, mystring, myobj, {boolarg: true, funcarg: my_func_that_returns_bool}); 'lub coś w tym stylu, aby było jednoznaczne co to jest. Następnie użytkownik musi upewnić się, że 'my_func_that_returns_bool' robi to, co twierdzi – Brandin

Odpowiedz

1

Meszal dokonał przewidywanie w pytaniu:

"... one will either be a boolean or a function that returns a boolean." 
"... first function, if it exists, will always return a boolean." 

Z tej przepowiedni funkcja nie jest maszyna Turinga, ponieważ wiemy, że zwraca coś. Z pewnością nie można tego zrobić za pomocą prostego RegExp: po prostu return !0 złamałby ten przykład.

Ale jeśli parsować wynik function.toString() z parserem wystarczająco inteligentnym, aby znaleźć wszystkie możliwe punkty zwrotne, problem powinien być zasadniczo rozwiązalny.

0

Interesujące pytanie, jeśli dobrze rozumiem. Po pierwsze, prawdopodobnie ostrzegłbym przed takimi otwartymi argumentami. Jestem ciekawy co do przypadku użycia.

Ale to powiedziawszy, łatwo jest ominąć problemy, o których wspomniałeś (co może nie w pełni rozwiązać twój problem).

Działa to w zasadzie; jednak uruchomiony typ BoolOrFunc() wykonuje funkcję ...

Łatwo to naprawić, jak sądzę. Najpierw sprawdź, czy BoolOrFunc jest wartością logiczną lub funkcją (tylko typeof BoolOrFunc, natch). Jeśli jest to boolean, zakładam, że nic nam nie jest. Brakuje SecondFunc (undefined) lub function - lub jesteśmy w stanie błędu. To wszystko jest łatwe w obsłudze w tym pierwszym przypadku.

Więc załóżmy drugą sprawę, że mamy BoolOrFunc-As-Function. Jedziemy musiał go wykonać, czy to „naprawdę” BoolOrFunclubSecondFunc, więc w ostatniej chwili możliwego w kodzie, należy to zrobić.

To jest oczywiście, gdy robi się skomplikowana bez więcej pseudo-kod (lub kodu produkcyjnego) od ciebie. Jeśli "możliwe BoolOrFunc" zwraca true lub false, wiesz, że masz wersję funkcji BoolOrFunc. Jeśli zwróci ona undefined, wiesz, że właśnie zadzwoniłeś pod numer SecondFunc. Znowu, w zależności od tego, co próbujesz zrobić, rozgałęzisz się tutaj. Jeśli masz true lub false, musisz przetworzyć "BoolOrFunc-as-function", inaczej zadzwoniłeś pod numer SecondFunc i prawdopodobnie skończyłeś.

To nie jest odpowiedź na bardziej ogólne pytanie, w jaki sposób stwierdzić, czy funkcja zwraca konkretny typ bez nazywając ją, ale nie rozwiązuje swój przypadek użycia przedstawione tutaj.

Ale ten szczególny przypadek bardziej ogólny [sic] nie jest zbyt trudne, o ile mamy do czynienia z rzeczywistych, stałych logicznych w return s. W takim przypadku trasa regexp zadziała - znajdź wszystkie return\s+.*; i upewnij się, że następujące po każdym return jest true lub false. Lub po prostu porównaj całkowitą liczbę return jest taka sama jak w przypadku return\s+(false|true);. Lub coś. I mam nadzieję, że javascript w funkcji jest dobrze sformułowany. Co za niedźwiedź już.

Jeśli funkcja może zwrócić zmienne lokalne (return MightBeBoolean; zamiast return true;), jesteś prawie tosty - lub jeśli przyjąć truthiness lub falsiness, jesteś prawie tosty ponownie, ponieważ undefined jest falsey, i nie można powiedzieć różnicę między BoolOrFunc lub SecondFunc (które zawsze zwracają "falsey"). Jest to możliwe, ale nie warto napisać parsera w jakimkolwiek rozsądnym przypadku, jaki mogę sobie wyobrazić. A jeśli importujesz do tego bibliotekę, sheesh. Powodzenia. Wydaje się, że overkill ma funkcję, która jest nieco bardziej defensywna w swoim powołaniu.

Zastanawiam się, czy zarówno funkcje przekazane jako argumenty przekazywane są same argumenty ze swoimi Obj.func, które domiar jeszcze bardziej interesująca.

Masz więcej prawdziwego kodu? ; ^) Ale ostatecznie zalecam, abyś nie "przekazywał żadnych zbieraniny argumentów, o ile są w porządku". Myślę, że możesz prawdopodobnie wykonać późną ocenę BoolOrFunc/SecondFunc. W przeciwnym razie nie znoszę tego powiedzieć, ale w tym miejscu zakodowałem jeszcze bardziej z.

Powiązane problemy