Czy istnieje sposób na zezwolenie na „nieograniczoną” zmienną dla funkcji w JavaScript?
Przykład:
load(var1, var2, var3, var4, var5, etc...)
load(var1)
Czy istnieje sposób na zezwolenie na „nieograniczoną” zmienną dla funkcji w JavaScript?
Przykład:
load(var1, var2, var3, var4, var5, etc...)
load(var1)
Odpowiedzi:
Jasne, po prostu użyj arguments
obiektu.
function foo() {
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
arguments
jest specjalnym obiektem „podobnym do tablicy”, co oznacza, że ma długość, ale nie ma innych funkcji tablicy. Aby uzyskać więcej informacji, zobacz developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ ... i ta odpowiedź: stackoverflow.com/a/13145228/1766230
length
właściwość. Obejmuje to arguments
obiekt. Wiedząc o tym i że metoda concat
zwraca kopię na tablicy „” To się nazywa dalej, możemy łatwo przekształcić arguments
obiekt do prawdziwej tablicy tak: var args = [].concat.call(arguments)
. Niektórzy wolą używać Array.prototype.concat.call
zamiast tego, ale podoba mi się to []
, że są krótkie i słodkie!
[...arguments].join()
W (najnowszych) przeglądarkach możesz przyjmować zmienną liczbę argumentów za pomocą tej składni:
function my_log(...args) {
// args is an Array
console.log(args);
// You can pass this array as parameters to another function
console.log(...args);
}
Oto mały przykład:
function foo(x, ...args) {
console.log(x, args, ...args, arguments);
}
foo('a', 'b', 'c', z='d')
=>
a
Array(3) [ "b", "c", "d" ]
b c d
Arguments
0: "a"
1: "b"
2: "c"
3: "d"
length: 4
Dokumentacja i więcej przykładów tutaj: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters
Inną opcją jest przekazanie argumentów w obiekcie kontekstowym.
function load(context)
{
// do whatever with context.name, context.address, etc
}
i użyj tego w ten sposób
load({name:'Ken',address:'secret',unused:true})
Ma to tę zaletę, że można dodać dowolną liczbę nazwanych argumentów, a funkcja może ich używać (lub nie) według własnego uznania.
context
argument za pomocą kodu i przekazać go, zanim zostanie wykorzystany.
Zgadzam się z odpowiedzią Kena jako najbardziej dynamiczną i lubię iść o krok dalej. Jeśli jest to funkcja, którą wywołujesz wiele razy z różnymi argumentami - używam projektu Kena, ale następnie dodam wartości domyślne:
function load(context) {
var defaults = {
parameter1: defaultValue1,
parameter2: defaultValue2,
...
};
var context = extend(defaults, context);
// do stuff
}
W ten sposób, jeśli masz wiele parametrów, ale niekoniecznie musisz je ustawiać przy każdym wywołaniu funkcji, możesz po prostu określić wartości domyślne. W przypadku metody ext możesz użyć metody jQuery's ext ( $.extend()
), stworzyć własną lub zastosować następujące:
function extend() {
for (var i = 1; i < arguments.length; i++)
for (var key in arguments[i])
if (arguments[i].hasOwnProperty(key))
arguments[0][key] = arguments[i][key];
return arguments[0];
}
Spowoduje to scalenie obiektu kontekstu z wartościami domyślnymi i wypełnienie wszelkich niezdefiniowanych wartości w twoim obiekcie wartościami domyślnymi.
_.defaults()
Metoda podkreślenia jest bardzo dobrą alternatywą do łączenia określonych i domyślnych argumentów.
Lepiej jest używać składni parametru rest, jak wskazał Ramast.
function (a, b, ...args) {}
Chcę tylko dodać jakąś fajną właściwość argumentu ... args
- Jest to tablica, a nie obiekt podobny do argumentów. Umożliwia to bezpośrednie zastosowanie funkcji takich jak mapa lub sortowanie.
- Nie obejmuje wszystkich parametrów, ale tylko jeden przekazany z niego dalej. Np. Funkcja (a, b, ... args) w tym przypadku args zawiera argument 3 do arguments.length
Jak już wspomniano, możesz użyć arguments
obiektu do pobrania zmiennej liczby parametrów funkcji.
Jeśli chcesz wywołać inną funkcję z tymi samymi argumentami, użyj apply
. Możesz nawet dodawać lub usuwać argumenty, konwertując arguments
na tablicę. Na przykład ta funkcja wstawia tekst przed zalogowaniem się do konsoli:
log() {
let args = Array.prototype.slice.call(arguments);
args = ['MyObjectName', this.id_].concat(args);
console.log.apply(console, args);
}
Chociaż ogólnie zgadzam się, że metoda nazwanych argumentów jest użyteczna i elastyczna (chyba że zależy ci na kolejności, w którym to przypadku argumenty są najłatwiejsze), mam obawy co do kosztu podejścia mbeasley (używanie domyślnych i rozszerzeń). Jest to ogromna kwota, jaką trzeba wziąć za wyciągnięcie wartości domyślnych. Po pierwsze, wartości domyślne są zdefiniowane w funkcji, więc są ponownie wypełniane przy każdym wywołaniu. Po drugie, możesz łatwo odczytać nazwane wartości i jednocześnie ustawić wartości domyślne za pomocą ||. Nie ma potrzeby tworzenia ani łączenia kolejnego nowego obiektu, aby uzyskać te informacje.
function load(context) {
var parameter1 = context.parameter1 || defaultValue1,
parameter2 = context.parameter2 || defaultValue2;
// do stuff
}
Jest to w przybliżeniu ta sama ilość kodu (może nieco więcej), ale powinna stanowić ułamek kosztów środowiska wykonawczego.
(parameter1=context.parameter1)===undefined && (parameter1=defaultValue1)
lub dla mniejszej objętości kodu mała funkcja pomocnicza, taka jak: function def(providedValue, default) {return providedValue !== undefined ? providedValue : defaultValue;} var parameter1 = def(context.parameter1, defaultValue1)
zapewnia alternatywne wzorce. Jednak mój punkt widzenia jest nadal słuszny: tworzenie dodatkowych obiektów dla każdego wywołania funkcji i uruchamianie drogich pętli w celu ustawienia kilku wartości domyślnych jest szalonym nakładem pracy.
Podczas gdy @roufamatic pokazał użycie słowa kluczowego arguments, a @Ken pokazał świetny przykład obiektu do użycia, nie wydaje mi się, aby naprawdę zajął się tym, co dzieje się w tym przypadku i może dezorientować przyszłych czytelników lub zaszczepić złą praktykę, ponieważ nie określa wyraźnie funkcji Metoda / ma na celu przyjmowanie zmiennej liczby argumentów / parametrów.
function varyArg () {
return arguments[0] + arguments[1];
}
Gdy inny programista przegląda Twój kod, bardzo łatwo jest założyć, że ta funkcja nie przyjmuje parametrów. Zwłaszcza jeśli programista nie jest wtajemniczony w słowo kluczowe arguments . Z tego powodu dobrym pomysłem jest przestrzeganie wytycznych dotyczących stylu i zachowanie spójności. Będę używać Google do wszystkich przykładów.
Powiedzmy wprost, że ta sama funkcja ma zmienne parametry:
function varyArg (var_args) {
return arguments[0] + arguments[1];
}
Może się zdarzyć, że obiekt jest potrzebny, ponieważ jest to jedyna zatwierdzona i uważana metoda najlepszej praktyki mapy danych. Tablice asocjacyjne są odrzucone i zniechęcone.
SIDENOTE: Słowo kluczowe argumenty faktycznie zwraca obiekt za pomocą liczb jako klucza. Dziedziczenie prototypowe jest także rodziną obiektów. Zobacz koniec odpowiedzi dla właściwego użycia tablicy w JS
W tym przypadku możemy to również wyraźnie stwierdzić. Uwaga: ta konwencja nazewnictwa nie jest dostarczana przez Google, ale jest przykładem wyraźnej deklaracji typu parametru. Jest to ważne, jeśli chcesz utworzyć bardziej ścisły wzór w kodzie.
function varyArg (args_obj) {
return args_obj.name+" "+args_obj.weight;
}
varyArg({name: "Brian", weight: 150});
To zależy od potrzeb twojej funkcji i programu. Jeśli na przykład chcesz zwrócić wartość na podstawie iteracyjnego procesu dla wszystkich przekazanych argumentów, z pewnością trzymaj się słowa kluczowego arguments . Jeśli potrzebujesz definicji argumentów i mapowania danych, wybierz metodę obiektową. Spójrzmy na dwa przykłady i gotowe!
function sumOfAll (var_args) {
return arguments.reduce(function(a, b) {
return a + b;
}, 0);
}
sumOfAll(1,2,3); // returns 6
function myObjArgs(args_obj) {
// MAKE SURE ARGUMENT IS AN OBJECT OR ELSE RETURN
if (typeof args_obj !== "object") {
return "Arguments passed must be in object form!";
}
return "Hello "+args_obj.name+" I see you're "+args_obj.age+" years old.";
}
myObjArgs({name: "Brian", age: 31}); // returns 'Hello Brian I see you're 31 years old
Jak wspomniano na górze odpowiedzi, słowo kluczowe argumenty faktycznie zwraca obiekt. Z tego powodu należy wywołać dowolną metodę, której chcesz użyć dla tablicy. Przykład tego:
Array.prototype.map.call(arguments, function (val, idx, arr) {});
Aby tego uniknąć, użyj parametru rest:
function varyArgArr (...var_args) {
return var_args.sort();
}
varyArgArr(5,1,3); // returns 1, 3, 5
Użyj arguments
obiektu znajdującego się w funkcji, aby mieć dostęp do wszystkich przekazanych argumentów.
Należy pamiętać, że przekazanie obiektu o nazwanych właściwościach, jak sugeruje Ken, zwiększa koszt przydzielania i zwalniania obiektu tymczasowego do każdego wywołania. Przekazywanie normalnych argumentów przez wartość lub odwołanie będzie na ogół najbardziej wydajne. Jednak w wielu aplikacjach wydajność nie jest krytyczna, ale w niektórych przypadkach może być.