Bagaimana saya bisa mengonversi objek "argumen" ke array di JavaScript?

432

The argumentsobyek dalam JavaScript adalah kutil-aneh bertindak seperti sebuah array dalam kebanyakan situasi, tapi itu tidak benar-benar sebuah objek array. Karena itu benar-benar sesuatu yang lain sama sekali , tidak memiliki fungsi yang berguna dari Array.prototypeseperti forEach, sort, filter, dan map.

Sangat mudah untuk membangun array baru dari objek argumen dengan simpel untuk loop. Misalnya, fungsi ini mengurutkan argumennya:

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

Namun, ini adalah hal yang agak menyedihkan yang harus dilakukan hanya untuk mendapatkan akses ke fungsi array JavaScript yang sangat berguna. Apakah ada cara bawaan untuk melakukannya menggunakan pustaka standar?

Andrew Coleson
sumber

Jawaban:

724

ES6 menggunakan parameter istirahat

Jika Anda dapat menggunakan ES6, Anda dapat menggunakan:

Parameter Istirahat

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

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

Seperti yang dapat Anda baca di tautan

Sintaks parameter lainnya memungkinkan kita untuk mewakili jumlah argumen yang tidak terbatas sebagai array.

Jika Anda penasaran dengan ...sintaksnya, ini disebut Penyebar Operator dan Anda dapat membaca lebih lanjut di sini .

ES6 menggunakan Array.from ()

Menggunakan 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 cukup konversi objek seperti Array atau Iterable ke dalam instance Array.



ES5

Anda benar-benar dapat hanya menggunakan Array's slicefungsi pada objek argumen, dan itu akan mengubahnya menjadi array JavaScript standar. Anda hanya perlu merujuknya secara manual melalui prototipe Array:

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

Mengapa ini bekerja? Nah, inilah kutipan dari dokumentasi ECMAScript 5 itu sendiri :

CATATAN : sliceFungsi ini sengaja dibuat generik; itu tidak mengharuskan nilai ini menjadi objek Array. Oleh karena itu dapat ditransfer ke objek jenis lain untuk digunakan sebagai metode. Apakah slicefungsi dapat diterapkan dengan sukses ke objek host tergantung implementasi.

Oleh karena itu, slicebekerja pada apa pun yang memiliki lengthproperti, yang argumentsnyaman melakukannya.


Jika Array.prototype.sliceterlalu sulit untuk Anda, Anda bisa menyingkatnya sedikit dengan menggunakan literal array:

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

Namun, saya cenderung merasa bahwa versi sebelumnya lebih eksplisit, jadi saya lebih suka itu. Menyalahgunakan array notasi literal terasa hacky dan terlihat aneh.

Jonathan Fingland
sumber
5
Di versi Firefox terbaru (2.0?) Dan ECMAScript 5, ada metode Array.slice yang membuatnya lebih sederhana. Anda akan menyebutnya seperti ini: var arge = Array.slice (argumen, 0) ;.
Matthew Crumley
9
Untuk apa 0? Karena tidak ada argumen yang ingin Anda sampaikan, mengapa Anda tidak bisa menggunakan saja var args = Array.prototype.slice.call(arguments);? [ Halaman argumen MDC ] ( developer.mozilla.org/en/JavaScript/Reference/… ) menyarankan metode tanpa 0.
Peter Ajtai
3
@ Barney - pengurutan ini diperlukan karena pertanyaan awal ingin mengurutkan argumen. Jika Anda hanya ingin mengubahnya menjadi sebuah array, itu tidak perlu.
Krease
17
"Anda tidak boleh mengiris argumen karena itu mencegah optimasi dalam mesin JavaScript (misalnya V8)." - dari MDN developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
frameworkninja
3
Saya tidak yakin menjawab pertanyaan awal. Waktu berlalu. Dengan ES6 bereksperimen di Firefox dan Chrome, parameter sisanya menjadi alternatif yang baik - function sortArgs(...argsToSort) { return argsToSort.sort(); }dari MDN developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Kir Kanos
40

Layak juga merujuk pada halaman wiki Bluebird menjanjikan perpustakaan ini yang menunjukkan cara mengelola argumentsobjek ke dalam array dengan cara yang membuat fungsi dioptimalkan di bawah mesin JavaScript V8 :

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

Metode ini digunakan untuk mendukung var args = [].slice.call(arguments);. Penulis juga menunjukkan bagaimana langkah pembangunan dapat membantu mengurangi verbositas.

jbmusso
sumber
2
+1 dan terima kasih atas tautannya ke halaman Bluebird Optimization Killer. PS: Saya baru-baru ini melihat optimasi ini digunakan dalam proyek node-thunkify .
Yves M.
29
function sortArgs(){ return [].slice.call(arguments).sort() }

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

Beberapa metode array sengaja dibuat untuk tidak memerlukan objek target menjadi array yang sebenarnya. Mereka hanya membutuhkan target untuk memiliki properti bernama panjang dan indeks (yang harus nol atau bilangan bulat lebih besar).

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

Menggunakan:

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

Array(arg1, arg2, ...) kembali [arg1, arg2, ...]

Array(str1) kembali [str1]

Array(num1) mengembalikan array yang memiliki num1 elemen

Anda harus memeriksa sejumlah argumen!

Array.slice versi (lebih lambat):

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

Array.push versi (lebih lambat, lebih cepat dari slice):

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

Pindahkan versi (lebih lambat, tetapi ukuran kecil lebih cepat):

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

Array.concat versi (paling lambat):

function sortArguments() {
  return Array.prototype.concat.apply([], arguments).sort();
}
LightSpeedC Kazuaki Nishizawa
sumber
1
Perhatikan bahwa karena perilaku perataan di Array.concat, ia akan menerima argumen array. sortArguments (2, [3,0], 1) mengembalikan 0,1,2,3.
Hafthor
9

Jika Anda menggunakan jQuery, yang berikut ini lebih mudah diingat menurut saya:

function sortArgs(){
  return $.makeArray(arguments).sort();
}
brad
sumber
1
Itu pada dasarnya apa yang saya cari di JS murni, tapi +1 untuk contoh kuat tentang bagaimana jQuery membuat JS sedikit lebih mudah untuk grok.
Andrew Coleson
2
"Kecuali jika tag lain untuk kerangka / pustaka juga disertakan, jawaban JavaScript murni diharapkan."
Michał Perłakowski
6

Dalam ECMAScript 6 tidak perlu menggunakan hacks jelek seperti Array.prototype.slice(). Anda bisa menggunakan sintaks spread ( ...) .

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

Ini mungkin terlihat aneh, tetapi cukup sederhana. Itu hanya mengekstrak argumentselemen dan mengembalikannya ke dalam array. Jika Anda masih tidak mengerti, lihat contoh ini:

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

Perhatikan bahwa itu tidak berfungsi di beberapa browser lama seperti IE 11, jadi jika Anda ingin mendukung browser ini, Anda harus menggunakan Babel .

Michał Perłakowski
sumber
5

Berikut ini adalah beberapa metode untuk mengubah argumen menjadi array.

Bagi saya, solusi terbaik untuk sejumlah kecil argumen adalah:

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

Untuk kasus lain:

function sortArgs (){ return Array.apply(null, arguments).sort(); }
Gheljenor
sumber
+1 untuk tolok ukur. Saat ini grafik menunjukkan Anda sortArgs6 kali lebih cepat di Firefox, tetapi dua kali lebih lambat di Chrome terbaru, dibandingkan dengan Array.apply.
joeytwiddle
1
Karena Array.prototype.slice sudah usang karena mencegah optimasi mesin JS V8 saya menganggap ini solusi terbaik sampai ES6 akan tersedia secara luas +1
Sasha
1
Selain itu metode generik Array seperti Array.slice () juga tidak digunakan lagi
Sasha
4

Saya sarankan menggunakan operator spread ECMAScript 6 , yang akan Mengikat parameter trailing ke array. Dengan solusi ini Anda tidak perlu menyentuh argumentsobjek dan kode Anda akan disederhanakan. Kelemahan dari solusi ini adalah tidak berfungsi di sebagian besar browser, jadi Anda harus menggunakan kompiler JS seperti Babel. Di bawah kap Babel berubah argumentsmenjadi Array dengan for for loop.

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

Jika Anda tidak dapat menggunakan ECMAScript 6, saya sarankan melihat beberapa jawaban lain seperti @Jonathan Fingland

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

Lodash:

var args = _.toArray(arguments);

dalam aksi:

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

menghasilkan:

[2,3]
Zane Hooper
sumber
6
Mengapa tidak _.toArray?
Menixator
5
Tetapi _.toArraylebih tepat.
Menixator
Saya akan berpendapat _.slice lebih tepat karena Anda sering ingin menjatuhkan beberapa argumen terkemuka.
Hafthor
4

Gunakan Array.from(), yang mengambil objek mirip array (seperti arguments) sebagai argumen dan mengubahnya menjadi array:

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

Perhatikan bahwa itu tidak berfungsi di beberapa browser lama seperti IE 11, jadi jika Anda ingin mendukung browser ini, Anda harus menggunakan Babel .

Michał Perłakowski
sumber
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
sumber
1

Jawaban Lain.

Gunakan Mantra Sihir Hitam:

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

Firefox, Chrome, Node.js, IE11 tidak masalah.

LightSpeedC Kazuaki Nishizawa
sumber
6
Ini jelas merupakan solusi terbaik ... jika Anda ingin membuat kode Anda benar-benar tidak dapat dibaca. Juga, __proto__sudah usang. Lihat dokumen MDN .
Michał Perłakowski
1

Coba gunakan Object.setPrototypeOf()

Penjelasan: Set prototypedari argumentskeArray.prototype

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

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


Penjelasan: Ambil setiap indeks arguments, tempatkan item ke dalam array di indeks array yang sesuai.

sebagai alternatif bisa digunakan Array.prototype.map()

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

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


Penjelasan: Ambil setiap indeks arguments, tempatkan item ke dalam array di indeks array yang sesuai.

for..of lingkaran

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

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


atau Object.create()

Penjelasan: Buat objek, atur properti objek ke item pada setiap indeks arguments; set prototypeobjek yang dibuat keArray.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
sumber
Anda telah bertanya kepada orang-orang apakah jawaban Anda memenuhi peringatan di bawah pertanyaan tentang "jawaban panjang". Menurut saya masalah utama dengan jawaban Anda adalah bahwa Anda tidak menjelaskan mengapa orang harus menggunakan salah satu metode yang Anda tunjukkan di sini. Tidak mungkin saya akan menggunakan salah satu solusi yang Anda usulkan karena semuanya lebih buruk daripada solusi dalam jawaban yang diterima. Misalnya, referensi Anda ke dokumen Object.setPrototypeOfperingatan bahwa itu adalah "operasi yang sangat lambat". Kenapa aku harus menggunakan ini Array.prototype.slice.call?
Louis
@Louis Diperbarui Jawaban dengan penjelasan untuk setiap pendekatan. Pertanyaan di OP tampaknya adalah "Apakah ada cara bawaan untuk melakukannya menggunakan perpustakaan standar?" , bukan "mengapa orang harus menggunakan salah satu metode" yang ada di dalamnya? Bagaimana mungkin setiap pengguna yang memposting Jawaban secara akurat menentukan apakah solusi yang diposting "tepat" untuk OP? Tampaknya terserah OP untuk menentukan ini? Sebenarnya, bagian notifikasi ini yang menarik bagi pengguna ini: "jelaskan mengapa jawaban Anda benar" . Apakah ada dari Jawaban yang diberikan pada status Pertanyaan ini: "Jawaban ini" benar "karena: x, y, z"?
tamu271314
Apa yang saya jelaskan adalah bagaimana SO secara umum bekerja. Apakah OP ingin tahu mengapa satu solusi lebih baik daripada solusi yang lain sama sekali tidak relevan, karena pertanyaan yang diposting untuk SO bukan terutama untuk OP tetapi untuk ratusan dan ribuan orang yang akan membaca pertanyaan dan jawabannya nanti. Juga, orang-orang yang memberikan suara pada jawaban tidak diharuskan untuk memilih sesuai dengan apa pun yang OP mungkin puas.
Louis
1

Inilah solusi yang bersih dan ringkas:

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

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

Object.values( )akan mengembalikan nilai-nilai dari sebuah objek sebagai array, dan karena argumentsmerupakan objek, pada dasarnya akan mengkonversi argumentske dalam array, sehingga memberikan Anda dengan semua fungsi pembantu array ini seperti map, forEach, filter, dll

Mistik
sumber
0

Metode Benshmarck 3:

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);

HASIL?

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

Nikmati !

Matriks
sumber
1
Ingin menyarankan untuk diubah ke sesuatu seperti arguments.length == 1?[arguments[0]]:Array.apply(null, arguments);untuk mencegah fungsi dipanggil dengan hanya satu argumen integer dummyFn(3)dan menyebabkan hasil[,,]
Nevermind
@nevermind pekerjaan yang baik, saya edit, versi Anda lebih baik;) Tapi saya tidak mengerti dummyFn(3)apa ini? fungsi ini tidak ada ...
Matrix
Uh ... sudahlah, hanya sebuah contoh yang ingin menunjukkan bagaimana suatu fungsi dipanggil hanya dengan satu argumen integer dan menyebabkan array kosong ukuran tetap, maaf untuk bahasa Inggris saya.
Nevermind
0

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

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

wsc
sumber
0

Meskipun parameter istirahat berfungsi dengan baik, jika Anda ingin terus menggunakan argumentsuntuk beberapa alasan, pertimbangkan

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

[...arguments]dapat dianggap semacam alternatif Array.from(arguments), yang juga berfungsi dengan baik.

Alternatif ES7 adalah pemahaman array:

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

Ini bisa termudah jika Anda ingin memproses atau memfilter argumen sebelum mengurutkan:

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

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

Saya mencoba teknik penghancuran sederhana

Gaurav
sumber
0

Objek argumen hanya tersedia di dalam fungsi tubuh. Meskipun Anda bisa mengindeks Objek Argumen seperti array, itu bukan array. Tidak memiliki properti array selain panjang.

// 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();

Meskipun dapat diindeks seperti array seperti yang Anda lihat dalam contoh ini:

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));

Namun, objek Argumen bukan array dan tidak memiliki properti lain selain panjang.

Anda bisa mengonversi objek argumen menjadi array di titik mana Anda dapat mengakses objek argumen.

Ada banyak cara Anda dapat mengakses objek argumen di dalam tubuh fungsi, dan ini termasuk:

  1. Anda dapat memanggil metode Array.prototoype.slice.call.

Array.prototype.slice.call (argumen)

function giveMeArgs(arg1,arg2){

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

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

  1. Anda bisa menggunakan array literal

[] .slice.call (argumen).

function giveMeArgs(arg1,arg2){

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

return args;

}

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

  1. Anda dapat menggunakan Istirahat ...

function giveMeArgs(...args){

return args;

}

console.log(giveMeArgs(1,2))

  1. Anda dapat menggunakan spread [...]

function giveMeArgs(){

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

}

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

  1. Anda dapat menggunakan Array.from ()

function giveMeArgs(){

var args = Array.from(arguments);

return args;

}

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

Rick
sumber
0

Anda dapat membuat fungsi yang dapat digunakan kembali untuk melakukannya dengan argumen apa pun, yang paling sederhana adalah sesuatu seperti ini:

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

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

Sintaks penyebaran dapat digunakan dalam ES6 dan di atas ...

Tetapi jika Anda ingin menggunakan sesuatu yang kompatibel dengan ES5 dan di bawah, Anda dapat menggunakan Array.prototype.slice.call, sehingga kode Anda terlihat seperti ini:

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

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

Ada juga beberapa cara lain untuk melakukan ini, untuk Contoh menggunakan Array.fromatau loop melalui argumen dan menetapkannya ke array baru ...

Alireza
sumber
-2

Ini adalah pertanyaan yang sangat lama, tetapi saya rasa saya memiliki solusi yang sedikit lebih mudah untuk diketik daripada solusi sebelumnya dan tidak bergantung pada perpustakaan eksternal:

function sortArguments() {
  return Array.apply(null, arguments).sort();
}
HandyAndyShortStack
sumber
2
Array.applytidak akan berfungsi jika Anda hanya memiliki satu argumen bilangan bulat positif. Itu karena new Array(3)menciptakan panjang array 3. Untuk lebih spesifik hasilnya akan [undefined, undefined, undefined]dan tidak [3].
inf3rno