2015-05-04 15 views
8

Szukam rozwiązania wanilii JavaScript.Argumenty funkcji JavaScript: pozycyjna -> zmiana mapy

Say Mam funkcji z następującym nagłówkiem:

generateEmail(firstName, lastname, provider) 

trzeba uruchomić go tak:

generateEmail("John","Smith","gmail.com"); 

Chciałbym, aby móc nazwać argumentem z odwzorowanie zamiast argumentów pozycyjnych:, tj.

generateEmail({ 
    "firstName":"John", 
    "lastname": "Smith", 
    "provider": "gmail.com" 
}); 

I szukam już napisanego rozwiązania, aby zrobić to w JavaScript, ponieważ mam do dyspozycji nieograniczoną liczbę funkcji, takich jak generateEmail. Czy taka biblioteka istnieje?

Widziałem https://github.com/kilianc/node-introspect, który obsługuje introspekcję funkcji (zwracanie informacji o abstrakcyjnych parametrach funkcji). Ale brakuje drugiej części - mapowanie wywołania mapy na wywołanie pozycyjne.

Proszę mi powiedzieć, czy coś takiego istnieje.


edytuj: jeśli nie wyraziłem się jasno: nie chcę modyfikować oryginalnej funkcji argumentu pozycyjnego. Dostaję takie funkcje od zewnętrznego dostawcy, który może zaktualizować swój kod. Wolałabym mieć opakowanie, które może wywoływać oryginalną funkcję pod spodem i udostępniać API map-argumentów na zewnątrz.

+0

Można sprawdzić, czy 'firstName' jest obiektem, a następnie ponownie wywołać' generateEmail' z właściwymi argumentami. –

+1

@GaurangTandon to jest całkowicie to czego ** nie potrzebuję **.Potrzebuję ogólnej funkcji otoki, która obsługuje to, co napisałem. Mogę sam to napisać, ale najpierw chcę sprawdzić, czy coś takiego już istnieje. – ducin

+0

Powiedziałbym, używając kombinacji tego http://stackoverflow.com/questions/914968/inspect-the-names-values-of-arguments-in-definition-execution-of-a-javascrip i '. zastosuj "byłoby to możliwe. –

Odpowiedz

3

Zakładając, że mamy dostęp do introspect od node-introspect (co trwa funkcję i zwraca uporządkowaną listę argumentów nazw), można po prostu zrobić:

function objArgsify(fn) { 
    var argNames = introspect(fn); 
    return function(obj) { 
     return fn.apply(this, 
         argNames.map(function(a) { return obj[a]; }); 
    } 
} 

Nazwać przez:

var generateEmailWithObjArgs = objArgsify(generateEmail); 
generateEmailWithObjArgs({ 
    "firstName":"John", 
    "lastname": "Smith", 
    "provider": "gmail.com" 
}); 

To akceptuje funkcję, odczytuje jej nazwy argumentów, a następnie zwraca funkcję otoki, która akceptuje obiekt i używa nazw argumentów pozycji, aby wyciągnąć właściwości z argumentu obiektowego w poprawnej kolejności.

Ta funkcja używa argumentu obiektowego czasu połączenia jako mapy do przekształcenia tablicy ["firstName", "lastname", "provider"] w tablicę ["John", "Smith", "gmail.com"]. Tablica ta jest następnie używana z apply do wywoływania funkcji postional-argument.

+0

Znacznie ładniej niż moje rozwiązanie. –

+0

Miałem nadzieję, że istnieje biblioteka, która go obsługuje, po prostu nie chciałem wymyślać koła. W każdym razie twoje rozwiązanie ma na celu moje potrzeby; Myślałem o więcej: 'var argMapify = funkcja (fn, argValues, kontekst) { var argDefs = introspect (fn); return fn.apply (context, argDefs.map (function (arg) { return argValues ​​[arg]; })); } ' i wywołanie' argMapify (fn, {...}) ', ponieważ otrzymujesz funkcję od zewnętrznego dostawcy i wywołujesz funkcję w locie. – ducin

+1

Należy zachować ostrożność przy użyciu 'węzła-introspekcji', ponieważ analizuje on funkcję jako ciąg znaków. Wszystko, co wykracza poza regex (tutaj w przyszłości, mamy funkcje pojedynczej argumentacji ES6 z opcjonalnymi nawiasami) nie będzie analizowane. Krótko mówiąc, zachowaj ostrożność, jeśli rozważasz to w rzeczywistym użyciu. – davidjb

0

Coś

var orig_generateEmail = generateEmail; 
    var generateEmail = function (map) { 
       orig_generateEmail(map.firstName, map.lastname, map.provider); 
    }; 

Ale to oczywiście kończy się na liście statycznych „mapowania”.

2

bez użycia zewnętrznych bibliotek,

var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; 
var ARGUMENT_NAMES = /([^\s,]+)/g; 
function getParamNames(func) { 
    var fnStr = func.toString().replace(STRIP_COMMENTS, ''); 
    var result = fnStr.slice(fnStr.indexOf('(')+1, fnStr.indexOf(')')).match(ARGUMENT_NAMES); 
    if(result === null) 
    result = []; 
    return result; 
} 

function call(method, object) { 
    var params = getParamNames(method); 
    var arrParams = []; 
    for (var i = 0; i < params.length; i++) { 
     arrParams.push(object[params[i]]); 
    } 
    return method.apply(arrParams); 
} 

Wystarczy zadzwonić go call(generateEmail, generateEmailObject).