Jak uzyskać wycinek z „argumentów”

80

Wszystko, co wiesz, argumentsto specjalny obiekt, który przechowuje wszystkie argumenty przekazane do funkcji.

Dopóki nie jest to tablica - nie możesz użyć czegoś takiego jak arguments.slice(1).

A więc pytanie - jak pokroić wszystko oprócz pierwszego elementu arguments?

UPD :

wydaje się, że nie ma sposobu bez konwersji go na tablicę z

var args = Array.prototype.slice.call(arguments);

Jeśli ktoś wrzuci inne rozwiązanie, byłoby super, jeśli nie - sprawdzę pierwsze z linijką powyżej jako odpowiedź.

zerkms
źródło
+ zerkms rzeczywiście istnieje lepszy sposób niż pobranie argumentsi przekonwertowanie go na tablicę itp. Zobacz moją odpowiedź poniżej.
Umur Karagöz

Odpowiedzi:

20

Wtrącanie się w funkcje tablicowe nie jest w rzeczywistości konieczne.

Używanie składni parametrów rest ...rest jest czystsze i wygodniejsze.

Przykład

function argumentTest(first, ...rest) {
  console.log("First arg:" + first);

  // loop through the rest of the parameters
  for (let arg of rest) {
    console.log("- " + arg);
  }
}

// call your function with any number of arguments
argumentTest("first arg", "#2", "more arguments", "this is not an argument but a contradiction");

...Odpoczynek

Umur Karagöz
źródło
Tak, zgadzam się, że obecnie jest to wygodniejsze. Głosowałem za tobą, ale nie zmienię z mocą wsteczną zaznaczonej odpowiedzi z 5 lat.
zerkms
2
Teraz po kolejnym roku myślę, że najwyższy czas przejść na nowe standardy ES :-)
zerkms
to uczucie, gdy dostaniesz +15 punktów za roczną odpowiedź :-D
zerkms
133

P. Jak pokroić wszystko oprócz pierwszego elementu arguments?

Poniższe zwróci tablicę zawierającą wszystkie argumenty oprócz pierwszego:

var slicedArgs = Array.prototype.slice.call(arguments, 1);

Nie musisz argumentsnajpierw konwertować na tablicę, zrób to wszystko w jednym kroku.

nnnnnn
źródło
Uważam, że jest to wada. Jeśli jest tylko jeden dodatkowy argument (poza pierwszym), nic nie jest zwracane.
Trevor,
@Trevor - Nie, zwraca tablicę z jednym elementem, który jest drugim argumentem. (Dlaczego nic nie zwróci?)
nnnnnn
4
Zalecenie tutaj stwierdza, że ​​nie należy używać wycinka w argumentach, ponieważ zapobiega to optymalizacji silnika JavaScript.
Jonathan Lin
1
Bardziej szczegółowe wyjaśnienie można znaleźć tutaj
David Chase
4
@David - Link „w szczegółach” nadal mówi, że nie należy używać .slice()w programie arguments, ale jedynym podanym powodem jest to, że uniemożliwia to optymalizację funkcji przez silnik JS. Więc nie chodzi o to, że zawodzi, po prostu może działać wolniej. Nie mam zamiaru pisać kodu do optymalizacji w silniku JS dnia, a nie wtedy, gdy silnik jutra mógł rozwiązać problem optymalizacji, aw każdym razie różnica prawdopodobnie nie będzie zauważalna dla użytkownika w większości przypadkach. Lepiej jest najpierw napisać jasny i łatwy w utrzymaniu kod, a następnie wrócić i zoptymalizować tylko wtedy, gdy pojawi się wymierny problem z wydajnością.
nnnnnn
11

Możesz „kroić bez cięcia”, proceduralnie przechodząc przez obiekt arguments:

function fun() {
  var args = [];

  for (var i = 1; i < arguments.length; i++) {
    args.push(arguments[i]);
  }

  return args;
}

fun(1, 2, 3, 4, 5); //=> [2, 3, 4, 5]
Paul Rosania
źródło
2
Tak, działa, ale nie ma sensu, jeśli mamy .slice();-)
zerkms
Oczywiście jest łatwiejszy w użyciu Array.prototype.slice, ale Twoje pytanie dotyczyło innego sposobu.
Paul Rosania
tak, dzięki za to ;-) (choć oczywiście wiem o for:-P)
zerkms
Haha, mam nadzieję, że nie brzmię banalnie. Czasami przydatne informacje o SO!
Paul Rosania
3
+1 Wydaje się, że jest to jedyne poprawne rozwiązanie dla V8. Spójrz na test porównawczy optymalizacji tutaj: jsperf.com/leaky-args
Tom Auger
11

Z https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments :

Nie należy przecinać argumentów, ponieważ zapobiega to optymalizacji w silnikach JavaScript (na przykład V8). Zamiast tego spróbuj skonstruować nową tablicę, przechodząc przez obiekt arguments.

Zatem powyższa odpowiedź Paula Rosiany jest poprawna

bluescrubbie
źródło
4
Może tak. Ale nie rozumiem, jak silniki optymalizacyjne nie mogły potraktować jednej linii przyjętej odpowiedzi i zoptymalizować jej w dowolny sposób. Na dłuższą metę zawsze jest uciążliwe, jeśli zaczynamy kodować dla optymalizatorów (w danym dniu) - osobiście wolę przejrzystość kodu.
akauppi
2
„plasterek” się nie zmienia. Zwraca płytką kopię elementów z oryginalnej tablicy. Elementy oryginalnej tablicy są kopiowane do zwracanej tablicy. Dlatego nie mogę zrozumieć, jaka jest różnica między ręcznym kopiowaniem do nowej tablicy a plasterkiem.
Maxim
Od 2018 roku ostrzeżenia już nie ma. Chyba powinniśmy być bezpieczni.
GBF_Gabriel,
9

Może to być sposób:

var args = Array.from(arguments).slice(1);
Di Tran
źródło
W dzisiejszych czasach nie jest to wcale konieczne:function foo(...args)
zerkms
@zerkms Miałem odrzucić twoją sugestię ze względu na wydajność, ale mój test pokazuje parametry spoczynku jako najszybsze rozwiązanie! gist.github.com/18d590d12aef1e90d2ed262f4fab0c96
Cody Allan Taylor
Wdrożenia @CodyAllanTaylor poprawiają się. Chyba że masz naprawdę-naprawdę-naprawdę ważny powód, aby nie chciałbym trzymać się składni bardziej czytelny
zerkms
0

Możesz użyć metody [].slice.call(arguments, 1)

[] .slice zwróci obiekt funkcji plasterka i możesz go wywołać jako parametry argumentsi 1

Thierryk
źródło
Jakieś zmiany, które sprawdziłeś w opublikowanych odpowiedziach przed opublikowaniem swoich? Identyczna (a nawet nieco lepsza, ponieważ nie przypisuje tablicy jednorazowej) odpowiedź jest już wysłana i jest sprawdzana.
zerkms
0

Możesz użyć ... rest w funkcji, aby oddzielić pierwszy i resztę argumentów:

function foo(arr) {
  const [first, ...rest] = arguments;
  console.log(`first = ${first}`);
  console.log(`rest = ${rest}`);
}
//Then calling the function with 3 arguments:
foo(1,2,3)

ntarlapan
źródło
Tak, przyszłość jest tutaj, w końcu :-D
zerkms