Wie kann ich das Objekt "Argumente" in ein Array in JavaScript konvertieren?

433

Das arguments Objekt in JavaScript ist eine ungeradeen warzen es wirkt wie ein Array in den meisten Situationen, aber es ist nicht wirklich ein Array - Objekt. Da es sich um etwas wirklich ganz anderes , hat es nicht die nützlichen Funktionen aus Array.prototypewie forEach, sort, filter, und map.

Es ist trivial einfach, ein neues Array aus einem Argumentobjekt mit einer einfachen for-Schleife zu erstellen. Diese Funktion sortiert beispielsweise ihre Argumente:

function sortArgs() {
    var args = [];
    for (var i = 0; i < arguments.length; i++)
        args[i] = arguments[i];
    return args.sort();
}

Dies ist jedoch eine ziemlich erbärmliche Sache, um einfach auf die äußerst nützlichen JavaScript-Array-Funktionen zugreifen zu können. Gibt es eine integrierte Möglichkeit, dies mit der Standardbibliothek zu tun?

Andrew Coleson
quelle

Antworten:

725

ES6 mit Ruheparametern

Wenn Sie ES6 verwenden können, können Sie Folgendes verwenden:

Ruheparameter

function sortArgs(...args) {
  return args.sort(function (a, b) { return a - b; });
}

document.body.innerHTML = sortArgs(12, 4, 6, 8).toString();

Wie Sie im Link lesen können

Die Restparametersyntax ermöglicht es uns, eine unbestimmte Anzahl von Argumenten als Array darzustellen.

Wenn Sie neugierig auf die ...Syntax sind, heißt sie Spread Operator und Sie können hier mehr lesen .

ES6 mit Array.from ()

Verwenden von Array.from :

function sortArgs() {
  return Array.from(arguments).sort(function (a, b) { return a - b; });
}

document.body.innerHTML = sortArgs(12, 4, 6, 8).toString();

Array.from Konvertieren Sie einfach Array-ähnliche oder iterierbare Objekte in Array-Instanzen.



ES5

Sie können eigentlich nur nutzen Arrays‘ sliceauf Argumente Objektfunktion, und es wird es in eine Standard - JavaScript - Array konvertieren. Sie müssen es nur manuell über den Prototyp von Array referenzieren:

function sortArgs() {
    var args = Array.prototype.slice.call(arguments);
    return args.sort();
}

Warum funktioniert das? Hier ist ein Auszug aus der ECMAScript 5-Dokumentation selbst :

HINWEIS : Die sliceFunktion ist absichtlich allgemein gehalten. Es ist nicht erforderlich, dass dieser Wert ein Array-Objekt ist. Daher kann es zur Verwendung als Methode auf andere Arten von Objekten übertragen werden. Ob die sliceFunktion erfolgreich auf ein Hostobjekt angewendet werden kann, hängt von der Implementierung ab.

Funktioniert daher slicean allem, was eine lengthEigenschaft hat, was argumentsbequem ist.


Wenn Array.prototype.sliceIhnen der Mund voll ist, können Sie ihn mit Array-Literalen leicht abkürzen:

var args = [].slice.call(arguments);

Ich habe jedoch das Gefühl, dass die frühere Version expliziter ist, daher würde ich sie stattdessen bevorzugen. Der Missbrauch der wörtlichen Array-Notation fühlt sich hackig an und sieht seltsam aus.

Jonathan Fingland
quelle
5
In den neuesten Firefox-Versionen (2.0?) Und ECMAScript 5 gibt es eine Array.slice-Methode, die dies etwas einfacher macht. Sie würden es so nennen: var arge = Array.slice (Argumente, 0);.
Matthew Crumley
9
Wofür ist das 0? Da Sie keine Argumente übergeben möchten, warum können Sie diese nicht einfach verwenden var args = Array.prototype.slice.call(arguments);? [ Die MDC-Argumentationsseite ] ( developer.mozilla.org/en/JavaScript/Reference/… ) schlägt die Methode ohne das vor 0.
Peter Ajtai
3
@Barney - Die Sortierung ist erforderlich, da die ursprüngliche Frage die Argumente sortieren möchte. Wenn Sie es nur in ein Array konvertieren möchten, ist dies nicht erforderlich.
Krease
17
"Sie sollten nicht auf Argumente verzichten, da dies Optimierungen in JavaScript-Engines (z. B. V8) verhindert." - von MDN developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Frameworkninja
3
Ich bin mir nicht sicher, ob das die ursprüngliche Frage beantwortet. Zeit verging. Mit ES6, das in Firefox und Chrome experimentiert wurde, wird der Rest-Parameter zu einer guten Alternative - function sortArgs(...argsToSort) { return argsToSort.sort(); }von MDN developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Kir Kanos
40

Es lohnt sich auch, auf diese Wiki-Seite der Bluebird-Versprechungsbibliothek zu verweisen , die zeigt, wie das argumentsObjekt in einem Array so verwaltet wird, dass die Funktion unter der V8-JavaScript-Engine optimiert werden kann :

function doesntLeakArguments() {
    var args = new Array(arguments.length);
    for(var i = 0; i < args.length; ++i) {
        args[i] = arguments[i];
    }
    return args;
}

Diese Methode wird zugunsten von verwendet var args = [].slice.call(arguments);. Der Autor zeigt auch, wie ein Build-Schritt dazu beitragen kann, die Ausführlichkeit zu verringern.

jbmusso
quelle
2
+1 und danke für den Link zur Bluebird Optimization Killer Seite. PS: Ich habe kürzlich gesehen, dass diese Optimierung im Node-Thunkify- Projekt verwendet wird.
Yves M.
29
function sortArgs(){ return [].slice.call(arguments).sort() }

// Returns the arguments object itself
function sortArgs(){ return [].sort.call(arguments) }

Einige Array-Methoden sind absichtlich so konzipiert, dass das Zielobjekt kein tatsächliches Array sein muss. Sie erfordern nur, dass das Ziel eine Eigenschaft mit dem Namen Länge und Indizes hat (die ganzzahlig Null oder größer sein müssen).

[].sort.call({0:1, 1:0, length:2}) // => ({0:0, 1:1, length:2})
Matyr
quelle
12

Verwenden:

function sortArguments() {
  return arguments.length === 1 ? [arguments[0]] :
                 Array.apply(null, arguments).sort();
}

Array(arg1, arg2, ...) kehrt zurück [arg1, arg2, ...]

Array(str1) kehrt zurück [str1]

Array(num1)Gibt ein Array mit num1Elementen zurück

Sie müssen die Anzahl der Argumente überprüfen!

Array.slice Version (langsamer):

function sortArguments() {
  return Array.prototype.slice.call(arguments).sort();
}

Array.push Version (langsamer, schneller als Slice):

function sortArguments() {
  var args = [];
  Array.prototype.push.apply(args, arguments);
  return args.sort();
}

Version verschieben (langsamer, aber klein ist schneller):

function sortArguments() {
  var args = [];
  for (var i = 0; i < arguments.length; ++i)
    args[i] = arguments[i];
  return args.sort();
}

Array.concat Version (am langsamsten):

function sortArguments() {
  return Array.prototype.concat.apply([], arguments).sort();
}
LightSpeedC Kazuaki Nishizawa
quelle
1
Beachten Sie, dass aufgrund des Abflachungsverhaltens in Array.concat Array-Argumente akzeptiert werden. sortArguments (2, [3,0], 1) gibt 0,1,2,3 zurück.
Hafthor
9

Wenn Sie jQuery verwenden, ist Folgendes meiner Meinung nach viel einfacher zu merken:

function sortArgs(){
  return $.makeArray(arguments).sort();
}
Brad
quelle
1
Das ist im Wesentlichen das, wonach ich in reinem JS gesucht habe, aber +1 für das solide Beispiel, wie jQuery JS ein bisschen einfacher macht.
Andrew Coleson
2
"Sofern kein anderes Tag für ein Framework / eine Bibliothek enthalten ist, wird eine reine JavaScript-Antwort erwartet."
Michał Perłakowski
6

In ECMAScript 6 müssen keine hässlichen Hacks wie verwendet werden Array.prototype.slice(). Sie können stattdessen die Spread-Syntax ( ...) verwenden .

(function() {
  console.log([...arguments]);
}(1, 2, 3))

Es mag seltsam aussehen, ist aber ziemlich einfach. Es werden nur argumentsdie Elemente extrahiert und wieder in das Array eingefügt. Wenn Sie immer noch nicht verstehen, sehen Sie sich diese Beispiele an:

console.log([1, ...[2, 3], 4]);
console.log([...[1, 2, 3]]);
console.log([...[...[...[1]]]]);

Beachten Sie, dass dies in einigen älteren Browsern wie IE 11 nicht funktioniert. Wenn Sie diese Browser unterstützen möchten, sollten Sie Babel verwenden .

Michał Perłakowski
quelle
5

Hier ist ein Benchmark mehrerer Methoden, die Argumente in Arrays konvertieren.

Für mich ist die beste Lösung für eine kleine Anzahl von Argumenten:

function sortArgs (){
  var q = [];
  for (var k = 0, l = arguments.length; k < l; k++){
    q[k] = arguments[k];
  }
  return q.sort();
}

Für andere Fälle:

function sortArgs (){ return Array.apply(null, arguments).sort(); }
Gheljenor
quelle
+1 für Benchmarks. Derzeit zeigen die Grafiken, dass Sie sortArgsin Firefox sechsmal schneller sind, in Chrome jedoch doppelt so langsam wie im neuesten Chrome Array.apply.
Joeytwiddle
1
Da Array.prototype.slice veraltet ist, weil es die Optimierung der JS V8-Engine verhindert, halte ich dies für die beste Lösung, bis ES6
Sasha
1
Darüber hinaus sind Array-Generika-Methoden wie Array.slice () ebenfalls veraltet
Sasha
4

Ich empfehle die Verwendung des ECMAScript 6- Spread-Operators , der nachfolgende Parameter an ein Array bindet. Mit dieser Lösung müssen Sie das argumentsObjekt nicht berühren und Ihr Code wird vereinfacht. Der Nachteil dieser Lösung ist, dass sie in den meisten Browsern nicht funktioniert. Stattdessen müssen Sie einen JS-Compiler wie Babel verwenden. Unter der Haube verwandelt sich Babel argumentsin ein Array mit einer for-Schleife.

function sortArgs(...args) {
  return args.sort();
}

Wenn Sie kein ECMAScript 6 verwenden können, empfehle ich, einige der anderen Antworten wie @Jonathan Fingland zu lesen

function sortArgs() {
    var args = Array.prototype.slice.call(arguments);
    return args.sort();
}
jjbskir
quelle
4

Lodash:

var args = _.toArray(arguments);

in Aktion:

(function(){ console.log(_.toArray(arguments).splice(1)); })(1, 2, 3)

produziert:

[2,3]
Zane Hooper
quelle
6
Warum nicht _.toArray?
Menixator
5
Ist _.toArrayaber angemessener.
Menixator
Ich würde argumentieren, dass _.slice angemessener ist, da Sie häufig einige führende Argumente fallen lassen möchten.
Hafthor
4

Verwenden Sie Array.from()diese Option, um ein Array-ähnliches Objekt (z. B. arguments) als Argument zu verwenden und es in ein Array zu konvertieren:

(function() {
  console.log(Array.from(arguments));
}(1, 2, 3));

Beachten Sie, dass dies in einigen älteren Browsern wie IE 11 nicht funktioniert. Wenn Sie diese Browser unterstützen möchten, sollten Sie Babel verwenden .

Michał Perłakowski
quelle
3
function sortArg(){
var args = Array.from(arguments); return args.sort();
}

 function sortArg(){
    var args = Array.from(arguments); 
    return args.sort();
    }
 
 console.log(sortArg('a', 'b', 1, 2, '34', 88, 20, '19', 39, 'd', 'z', 'ak', 'bu', 90));

Abk
quelle
1

Eine andere Antwort.

Verwenden Sie Zauber der schwarzen Magie:

function sortArguments() {
  arguments.__proto__ = Array.prototype;
  return arguments.slice().sort();
}

Firefox, Chrome, Node.js, IE11 sind in Ordnung.

LightSpeedC Kazuaki Nishizawa
quelle
6
Dies ist definitiv die beste Lösung ... wenn Sie Ihren Code vollständig unlesbar machen möchten. Auch __proto__ist veraltet. Siehe MDN-Dokumente .
Michał Perłakowski
1

Versuchen Sie es mit Object.setPrototypeOf()

Erläuterung: Satz prototypevon argumentsbisArray.prototype

function toArray() {
  return Object.setPrototypeOf(arguments, Array.prototype)
} 

console.log(toArray("abc", 123, {def:456}, [0,[7,[14]]]))


Erläuterung: Nehmen Sie jeden Index von argumentsund platzieren Sie das Element in einem Array am entsprechenden Index des Arrays.

könnte alternativ verwenden Array.prototype.map()

function toArray() {
  return [].map.call(arguments, (_,k,a) => a[k])
} 

console.log(toArray("abc", 123, {def:456}, [0,[7,[14]]]))


Erläuterung: Nehmen Sie jeden Index von argumentsund platzieren Sie das Element in einem Array am entsprechenden Index des Arrays.

for..of Schleife

function toArray() {
 let arr = []; for (let prop of arguments) arr.push(prop); return arr
} 

console.log(toArray("abc", 123, {def:456}, [0,[7,[14]]]))


oder Object.create()

Erläuterung: Objekt erstellen, Eigenschaften des Objekts auf Elemente an jedem Index von setzen arguments; Satz prototypevon erstellten Objekten zuArray.prototype

function toArray() {
  var obj = {};
  for (var prop in arguments) {
    obj[prop] = {
      value: arguments[prop],
      writable: true,
      enumerable: true,
      configurable: true
    }
  } 
  return Object.create(Array.prototype, obj);
}

console.log(toArray("abc", 123, {def: 456}, [0, [7, [14]]]))

guest271314
quelle
Sie haben Leute gefragt, ob Ihre Antwort die Warnung unter der Frage nach "langen Antworten" erfüllt. Mir scheint, das Hauptproblem bei Ihrer Antwort ist, dass Sie nicht erklären, warum man eine der hier gezeigten Methoden anwenden sollte. Ich würde auf keinen Fall eine der von Ihnen vorgeschlagenen Lösungen verwenden, da sie alle schlechter sind als die Lösungen in der akzeptierten Antwort. Zum Beispiel Object.setPrototypeOfwarnt Ihr Verweis auf das Dokument von , dass es sich um eine "sehr langsame Operation" handelt. Warum um alles in der Welt sollte ich das über verwenden Array.prototype.slice.call?
Louis
@ Louis Aktualisierte Antwort mit Erläuterungen zu jedem Ansatz. Die Frage bei OP scheint zu lauten: "Gibt es eine integrierte Möglichkeit, dies mit der Standardbibliothek zu tun?" , nicht "warum sollte man eine der Methoden verwenden" , die eingebaut sind? Wie kann ein Benutzer, der eine Antwort veröffentlicht hat, genau feststellen, ob die veröffentlichten Lösungen für OP "richtig" sind? Es scheint, dass es an OP liegt, dies zu bestimmen? Eigentlich ist dieser Teil der Benachrichtigung das, was diesen Benutzer interessiert: "Erklären Sie, warum Ihre Antwort richtig ist" . Gibt eine der Antworten auf diese Frage an: "Diese Antwort ist" richtig ", weil: x, y, z"?
guest271314
Was ich erklärt habe ist, wie SO im Allgemeinen funktioniert. Ob das OP wissen möchte, warum eine Lösung besser ist als die andere, spielt keine Rolle, da die für SO gestellten Fragen nicht in erster Linie für das OP, sondern für Hunderte und Tausende von Personen bestimmt sind, die die Frage und ihre Antworten später lesen werden. Außerdem müssen die Personen, die über Antworten abstimmen, nicht entsprechend der Zufriedenheit des OP abstimmen.
Louis
1

Hier ist eine saubere und präzise Lösung:

function argsToArray() {
  return Object.values(arguments);
}

// example usage
console.log(
  argsToArray(1, 2, 3, 4, 5)
  .map(arg => arg*11)
);

Object.values( )die Werte eines Objekts als Array zurück, und da argumentsein Objekt ist, wird es im Wesentlichen wandeln argumentsin ein Array, so dass Sie mit allen eines Arrays Hilfsfunktionen wie die Bereitstellung von map, forEach, filteretc.

Mystisch
quelle
0

Benshmarck 3 Methoden:

function test()
{
  console.log(arguments.length + ' Argument(s)');

  var i = 0;
  var loop = 1000000;
  var t = Date.now();
  while(i < loop)
  {
      Array.prototype.slice.call(arguments, 0); 
      i++;
  }
  console.log(Date.now() - t);


  i = 0,
  t = Date.now();
  while(i < loop)
  {
      Array.apply(null, arguments);
      i++;
  }
  console.log(Date.now() - t);

  i = 0,
  t = Date.now();
  while(i < loop)
  {
      arguments.length == 1 ? [arguments[0]] : Array.apply(null, arguments);
      i++;
  }
  console.log(Date.now() - t);
}

test();
test(42);
test(42, 44);
test(42, 44, 88, 64, 10, 64, 700, 15615156, 4654, 9);
test(42, 'truc', 44, '47', 454, 88, 64, '@ehuehe', 10, 64, 700, 15615156, 4654, 9,97,4,94,56,8,456,156,1,456,867,5,152489,74,5,48479,89,897,894,894,8989,489,489,4,489,488989,498498);

ERGEBNIS?

0 Argument(s)
256
329
332
1 Argument(s)
307
418
4
2 Argument(s)
375
364
367
10 Argument(s)
962
601
604
40 Argument(s)
3095
1264
1260

Genießen !

Matrix
quelle
1
Ich möchte vorschlagen, zu etwas arguments.length == 1?[arguments[0]]:Array.apply(null, arguments);zu dummyFn(3)[,,]
ändern
@nevermind gute Arbeit, ich bearbeite, deine Version ist besser;) Aber ich verstehe nicht, dummyFn(3)was das ist? Diese Funktion existiert nicht ...
Matrix
Äh ... egal, nur ein Beispiel möchte zeigen, wie eine Funktion mit nur einem ganzzahligen Argument aufgerufen wird und ein leeres Array mit fester Größe verursacht. Entschuldigung für mein Englisch.
vergiss den
0

function sortArgs(...args) {
  return args.sort(function (a, b) { return a - b; });
}

document.body.innerHTML = sortArgs(1, 2, 3, 4).toString();

wsc
quelle
0

Obwohl Ruheparameter gut funktionieren, sollten Sie berücksichtigen, ob Sie sie argumentsaus irgendeinem Grund weiterhin verwenden möchten

function sortArgs() {
  return [...arguments].sort()
}

[...arguments]kann als eine Art Alternative zu betrachtet werden Array.from(arguments), die auch perfekt funktioniert.

Eine ES7-Alternative ist ein Array-Verständnis:

[for (i of arguments) i].sort()

Dies ist am einfachsten, wenn Sie die Argumente vor dem Sortieren verarbeiten oder filtern möchten:

[for (i of arguments) if (i % 2) Math.log(i)].sort()

quelle
0
 function x(){
   var rest = [...arguments]; console.log(rest);return     
   rest.constructor;
 };
 x(1,2,3)

Ich habe eine einfache Zerstörungstechnik ausprobiert

Gaurav
quelle
0

Das Arguments-Objekt ist nur innerhalb eines Funktionskörpers verfügbar. Obwohl Sie das Argumentobjekt wie ein Array indizieren können, handelt es sich nicht um ein Array. Es hat keine anderen Array-Eigenschaften als die Länge.

// function arguments length 5
function properties(a,b,c,d,e){
var function_name= arguments.callee.name
var arguments_length= arguments.length;
var properties_length=  properties.length; 
var function_from= properties.caller.name;
console.log('I am the function name: '+ function_name);
console.log('I am the function length, I am function spacific: '+ properties_length); 
console.log('I am the arguments length, I am context/excution spacific: '+ arguments_length);
console.log('I am being called From: '+  function_from );
}

// arguments 3
function parent(){
properties(1,2,3);
}

//arguments length 3 because execution spacific
parent();

Obwohl es wie ein Array indiziert werden kann, wie Sie in diesem Beispiel sehen können:

function add(){

var sum=0;

for(var i=0; i< arguments.length;i++){

sum = sum + arguments[i];

}

return sum;

}

console.log(add(1,2,3));

Das Arguments-Objekt ist jedoch kein Array und hat keine anderen Eigenschaften als die Länge.

Sie können das Argumentobjekt in ein Array konvertieren und an diesem Punkt auf das Argumentobjekt zugreifen.

Es gibt viele Möglichkeiten, auf das Argumentobjekt innerhalb eines Funktionskörpers zuzugreifen. Dazu gehören:

  1. Sie können die Array.prototoype.slice.call-Methode aufrufen.

Array.prototype.slice.call (Argumente)

function giveMeArgs(arg1,arg2){

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

console.log( giveMeArgs(1,2));

  1. Sie können das Array-Literal verwenden

[] .slice.call (Argumente).

function giveMeArgs(arg1,arg2){

var args = [].slice.call(arguments);

return args;

}

console.log( giveMeArgs(1,2) );

  1. Sie können Rest ...

function giveMeArgs(...args){

return args;

}

console.log(giveMeArgs(1,2))

  1. Sie können verbreiten [...]

function giveMeArgs(){

var args = [...arguments];
return args;

}

console.log(giveMeArgs(1,2));

  1. Sie können Array.from () verwenden

function giveMeArgs(){

var args = Array.from(arguments);

return args;

}

console.log(giveMeArgs(1,2));

Rick
quelle
0

Sie können eine wiederverwendbare Funktion erstellen, um dies mit beliebigen Argumenten zu tun. Die einfachste ist ungefähr so:

function sortArgs() {
  return [...arguments].sort();
}

sortArgs('ali', 'reza', 1, 2, 'a'); //[1, 2, "a", "ali", "reza"];

Die Spread-Syntax kann in ES6 und höher verwendet werden ...

Wenn Sie jedoch etwas verwenden möchten , das mit ES5 und niedriger kompatibel ist , können Sie Folgendes verwenden Array.prototype.slice.call, sodass Ihr Code folgendermaßen aussieht:

function sortArgs() {
  return Array.prototype.slice.call(arguments).sort();
}

sortArgs('ali', 'reza', 1, 2, 'a'); //[1, 2, "a", "ali", "reza"];

Es gibt auch einige andere Möglichkeiten, dies zu tun, zum Beispiel Array.fromdie Argumente zu verwenden oder zu durchlaufen und sie einem neuen Array zuzuweisen ...

Alireza
quelle
-2

Dies ist eine sehr alte Frage, aber ich glaube, ich habe eine Lösung, die etwas einfacher zu tippen ist als frühere Lösungen und nicht auf externen Bibliotheken basiert:

function sortArguments() {
  return Array.apply(null, arguments).sort();
}
HandyAndyShortStack
quelle
2
Array.applyfunktioniert nicht, wenn Sie nur ein einziges positives Integer-Argument haben. Dies liegt daran, dass new Array(3)eine Array-Länge von erstellt wird 3. Genauer gesagt wird das Ergebnis sein [undefined, undefined, undefined]und nicht [3].
inf3rno