Nazwane parametry w javascript

Uważam, że funkcja nazwanych parametrów w C# jest bardzo przydatna w niektórych przypadkach.

calculateBMI(70, height: 175);

Co jeśli chcę to w javascript ?


What I don ' t want is-

myFunction({ param1 : 70, param2 : 175});

function myFunction(params){
    //check if params is an object
    //check if the parameters I need are non-null
    //blah-blah
}

To podejście, które już zastosowałem. Jest inny sposób?

mogę używać każdej biblioteki. (Lub ktoś może wskazać mi taki, który już to robi)

Author: Bergi, 2012-08-03

7 answers

ES2015

W ES2015, destrukcja parametrów może być używana do symulacji nazwanych parametrów. Wymagałoby to, aby wywołujący przekazał obiekt, ale można uniknąć wszystkich sprawdzeń wewnątrz funkcji, jeśli również użyjesz domyślnych parametrów:

myFunction({ param1 : 70, param2 : 175});

function myFunction({param1, param2}={}){
  // ...
}

ES5

Jest sposób, aby zbliżyć się do tego, co chcesz, ale opiera się na wyjściu z Function.prototype.toString [ES5], która jest zależna od niektórych stopnia, więc może nie być kompatybilny z przeglądarkami.

Chodzi o to, aby przeanalizować nazwy parametrów z łańcuchowej reprezentacji funkcji, tak aby można było powiązać właściwości obiektu z odpowiednim parametrem.

Wywołanie funkcji może wtedy wyglądać jak

func(a, b, {someArg: ..., someOtherArg: ...});

Gdzie a i b są argumentami pozycyjnymi, a ostatni argument jest obiektem o nazwanych argumentach.

Na przykład:

var parameterfy = (function() {
    var pattern = /function[^(]*\(([^)]*)\)/;

    return function(func) {
        // fails horribly for parameterless functions ;)
        var args = func.toString().match(pattern)[1].split(/,\s*/);

        return function() {
            var named_params = arguments[arguments.length - 1];
            if (typeof named_params === 'object') {
                var params = [].slice.call(arguments, 0, -1);
                if (params.length < args.length) {
                    for (var i = params.length, l = args.length; i < l; i++) {
                        params.push(named_params[args[i]]);
                    }
                    return func.apply(this, params);
                }
            }
            return func.apply(null, arguments);
        };
    };
}());

Które byś użył as:

var foo = parameterfy(function(a, b, c) {
    console.log('a is ' + a, ' | b is ' + b, ' | c is ' + c);     
});

foo(1, 2, 3); // a is 1  | b is 2  | c is 3
foo(1, {b:2, c:3}); // a is 1  | b is 2  | c is 3
foo(1, {c:3}); // a is 1  | b is undefined  | c is 3
foo({a: 1, c:3}); // a is 1  | b is undefined  | c is 3 

DEMO

Istnieją pewne wady do tego podejścia (zostałeś ostrzeżony!):

    Jeśli ostatni argument jest obiektem, jest on traktowany jako "nazwane obiekty argumentu".]}
  • zawsze otrzymasz tyle argumentów, ile zdefiniowałeś w funkcji, ale niektóre z nich mogą mieć wartość undefined (różni się to od braku wartości w ogóle). Oznacza to, że nie można użyć arguments.length, aby sprawdzić, ile argumentów zostało zdałem.

Zamiast funkcji tworzącej wrapper, możesz również mieć funkcję, która przyjmuje funkcję i różne wartości jako argumenty, takie jak

call(func, a, b, {posArg: ... });

Lub nawet rozszerzyć Function.prototype tak, aby można było:

foo.execute(a, b, {posArg: ...});
 113
Author: Felix Kling,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-26 18:14:27

No - podejście obiektowe jest odpowiedzią JavaScript na to. Nie ma z tym problemu pod warunkiem, że funkcja oczekuje obiektu, a nie oddzielnych param.

 55
Author: Utkanos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-02 05:59:23

Ten problem od jakiegoś czasu jest dla mnie problemem. Jestem doświadczonym programistą z wieloma językami pod moim pasem. Jednym z moich ulubionych języków, z których miałem przyjemność korzystać, jest Python. Python obsługuje nazwane parametry bez żadnych sztuczek.... Odkąd zacząłem używać Pythona (jakiś czas temu) wszystko stało się łatwiejsze. Uważam, że każdy język powinien obsługiwać parametry nazwane, ale tak nie jest.

Wielu ludzi mówi, aby użyć sztuczki "podaj przedmiot", więc że masz nazwane parametry.

/**
 * My Function
 *
 * @param {Object} arg1 Named arguments
 */
function myFunc(arg1) { }

myFunc({ param1 : 70, param2 : 175});
I to działa świetnie, z wyjątkiem..... jeśli chodzi o Większość IDE, wielu z nas programistów polega na podpowiedziach typu / argumentu w naszym IDE. Ja osobiście używam PHP Storm (wraz z innymi Idami JetBrains jak PyCharm dla Pythona i AppCode dla Objective C)

A największym problemem z użyciem sztuczki "podaj obiekt" jest to, że podczas wywoływania funkcji, IDE daje podpowiedź jednego typu i to wszystko... Jak mamy to zrobić? wiesz jakie parametry i typy powinny trafić do obiektu arg1?

Nie mam pojęcia jakie parametry powinny iść w arg1

Więc... sztuczka "podaj przedmiot" nie działa na mnie... To faktycznie powoduje więcej bólów głowy z konieczności spojrzeć na każdej funkcji docblock zanim wiem, jakie parametry funkcja oczekuje.... Oczywiście, jest to świetne rozwiązanie, gdy zachowujesz istniejący kod, ale jest to straszne dla pisania nowego kodu. To jest technika, której używam.... Teraz mogą wystąpić pewne problemy, a niektórzy programiści mogą powiedz mi, że robię to źle, i mam otwarty umysł, jeśli chodzi o te rzeczy... Zawsze chętnie patrzę na lepsze sposoby realizacji zadania... Tak więc, jeśli jest problem z tą techniką, komentarze są mile widziane.
/**
 * My Function
 *
 * @param {string} arg1 Argument 1
 * @param {string} arg2 Argument 2
 */
function myFunc(arg1, arg2) { }

var arg1, arg2;
myFunc(arg1='Param1', arg2='Param2');
W ten sposób mam to, co najlepsze z obu światów... nowy kod jest łatwy do napisania, ponieważ moje IDE daje mi wszystkie odpowiednie podpowiedzi... I, zachowując kod później, mogę zobaczyć na pierwszy rzut oka, nie tylko wartość przekazaną do funkcji, ale także nazwę kłótnia. Jedyne, co widzę, to deklarowanie nazw argumentów jako zmiennych lokalnych, aby nie zanieczyszczać globalnej przestrzeni nazw. Oczywiście, jest to trochę dodatkowe pisanie, ale trywialne w porównaniu do czasu potrzebnego do wyszukania blokad dokumentów podczas pisania nowego kodu lub utrzymywania istniejącego kodu.

Teraz mam wszystkie parametry i typy podczas tworzenia nowego kodu

 17
Author: Ray Perea,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-10 20:06:24

Jeśli chcesz wyjaśnić, czym są każdy z parametrów, a nie tylko wywoływać

someFunction(70, 115);

Dlaczego nie wykonać następujących czynności

var width = 70, height = 115;
someFunction(width, height);

Jasne, to dodatkowa linia kodu, ale wygrywa pod względem czytelności.

 15
Author: dav_i,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-03 13:29:59

Innym sposobem byłoby użycie atrybutów odpowiedniego obiektu, np. tak:

function plus(a,b) { return a+b; };

Plus = { a: function(x) { return { b: function(y) { return plus(x,y) }}}, 
         b: function(y) { return { a: function(x) { return plus(x,y) }}}};

sum = Plus.a(3).b(5);

Oczywiście dla tego Zmyślonego przykładu jest to nieco bez znaczenia. Ale w przypadkach, gdy funkcja wygląda jak

do_something(some_connection_handle, some_context_parameter, some_value)
To może być bardziej przydatne. Można go również połączyć z pomysłem "parametryzacji", aby stworzyć taki obiekt z istniejącej funkcji w sposób ogólny. Czyli dla każdego parametru tworzyłby element, który może być oceniany do częściowej wersji funkcja. Ta idea jest oczywiście związana z Schönfinkeling aka Currying.
 4
Author: Udo Klein,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-07 15:40:38

Jest inny sposób. Jeśli przekazujesz obiekt przez odniesienie, jego właściwości pojawią się w lokalnym zakresie funkcji. Wiem, że działa to dla Safari (nie sprawdzałem innych przeglądarek) i nie wiem, czy ta funkcja ma nazwę, ale poniższy przykład ilustruje jej użycie.

Chociaż w praktyce nie wydaje mi się, aby to oferowało jakąkolwiek wartość funkcjonalną poza techniką, której już używasz, jest trochę czystsze semantycznie. I nadal wymaga podania obiektu odniesienie lub obiekt dosłowny.

function sum({ a:a, b:b}) {
    console.log(a+'+'+b);
    if(a==undefined) a=0;
    if(b==undefined) b=0;
    return (a+b);
}

// will work (returns 9 and 3 respectively)
console.log(sum({a:4,b:5}));
console.log(sum({a:3}));

// will not work (returns 0)
console.log(sum(4,5));
console.log(sum(4));
 3
Author: Allen Ellison,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-02 23:43:58

Próba Node-6.4.0 (process.wersje.v8 = '5.0.71.60') i Node Chakracore-v7.0. 0-pre8, a następnie Chrome-52 (V8=5.2.361.49), zauważyłem, że nazwane parametry są prawie zaimplementowane, ale ta kolejność nadal ma pierwszeństwo. Nie mogę znaleźć tego, co mówi norma ECMA.

>function f(a=1, b=2){ console.log(`a=${a} + b=${b} = ${a+b}`) }

> f()
a=1 + b=2 = 3
> f(a=5)
a=5 + b=2 = 7
> f(a=7, b=10)
a=7 + b=10 = 17

Ale zamówienie jest wymagane!! Czy to standardowe zachowanie?

> f(b=10)
a=10 + b=2 = 12
 2
Author: jgran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-18 09:17:47