Apakah mungkin untuk mengirim sejumlah variabel argumen ke fungsi JavaScript?

171

Apakah mungkin untuk mengirim sejumlah variabel argumen ke fungsi JavaScript, dari sebuah array?

var arr = ['a','b','c']

var func = function()
{
    // debug 
    alert(arguments.length);
    //
    for(arg in arguments)
        alert(arg);
}

func('a','b','c','d'); // prints 4 which is what I want, then 'a','b','c','d'
func(arr); // prints 1, then 'Array'

Saya baru-baru ini menulis banyak Python dan itu adalah pola yang bagus untuk dapat menerima varargs dan mengirimkannya. misalnya

def func(*args):
   print len(args)
   for i in args:
       print i

func('a','b','c','d'); // prints 4 which is what I want, then 'a','b','c','d'
func(*arr) // prints 4 which is what I want, then 'a','b','c','d'

Apakah mungkin dalam JavaScript untuk mengirim array untuk diperlakukan sebagai array argumen?

Fire Crow
sumber
4
Perhatikan bahwa ini bukan ide yang baik untuk menggunakan for - inloop dengan argumentsobjek - 'normal' untuk iterasi loop di atas lengthproperti harus digunakan sebagai gantinya
Yi Jiang
2
itu tidak pernah menjadi masalah, bisakah Anda menjelaskan mengapa itu terjadi? objek argumen hampir selalu cukup kecil untuk memiliki peningkatan kinerja yang dapat diabaikan untuk menggunakan versi agrument [0..length-1].
Fire Crow
Kemungkinan duplikat jumlah variabel JavaScript untuk berfungsi
Anderson Green
1
Saya pikir argumen bukan array aktual, tetapi objek khusus, jadi sintaks "in" mungkin tidak berfungsi, tergantung pada implementasi JS.
O'Rooney

Jawaban:

209

Pembaruan : Sejak ES6, Anda cukup menggunakan sintaks penyebaran saat memanggil fungsi:

func(...arr);

Karena ES6 juga jika Anda berharap untuk memperlakukan argumen Anda sebagai array, Anda juga dapat menggunakan sintaks spread dalam daftar parameter, misalnya:

function func(...args) {
  args.forEach(arg => console.log(arg))
}

const values = ['a', 'b', 'c']
func(...values)
func(1, 2, 3)

Dan Anda dapat menggabungkannya dengan parameter normal, misalnya jika Anda ingin menerima dua argumen pertama secara terpisah dan sisanya sebagai array:

function func(first, second, ...theRest) {
  //...
}

Dan mungkin bermanfaat bagi Anda, bahwa Anda dapat mengetahui berapa banyak argumen yang diharapkan oleh suatu fungsi:

var test = function (one, two, three) {}; 
test.length == 3;

Tapi bagaimanapun, Anda dapat melewati sejumlah argumen arbitrer ...

Sintaksis penyebaran lebih pendek dan "lebih manis" daripada applydan jika Anda tidak perlu menetapkan thisnilai dalam pemanggilan fungsi, inilah cara yang harus dilakukan.

Berikut ini contoh yang berlaku , yang merupakan cara sebelumnya untuk melakukannya:

var arr = ['a','b','c'];

function func() {
  console.log(this); // 'test'
  console.log(arguments.length); // 3

  for(var i = 0; i < arguments.length; i++) {
    console.log(arguments[i]);
  }

};

func.apply('test', arr);

Saat ini saya hanya merekomendasikan menggunakan applyhanya jika Anda harus melewati sejumlah argumen dari array dan mengatur thisnilainya. applytake adalah thisnilai sebagai argumen pertama, yang akan digunakan pada pemanggilan fungsi, jika kita menggunakan nullkode non-ketat, thiskata kunci akan merujuk ke objek Global (jendela) di dalam func, dalam mode ketat, ketika secara eksplisit menggunakan 'gunakan ketat 'atau dalam modul ES, nullakan digunakan.

Perhatikan juga bahwa argumentsobjek tersebut bukan Array, Anda dapat mengubahnya dengan:

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

Dan dalam ES6:

const argsArray = [...arguments] // or Array.from(arguments)

Tetapi Anda jarang menggunakan argumentsobjek secara langsung saat ini berkat sintaksis penyebaran.

CMS
sumber
1
Terima kasih, terapkan melakukan trik, panggilan dalam kasus ini tidak berfungsi. Apakah itu ditulis secara tidak sengaja?
Fire Crow
Bagaimana Anda melakukannya jika fungsi sebenarnya adalah anggota kelas? Apakah ini benar? theObject.member.apply (theObject, argumen);
Baxissimo
4
Array.prototype.slice.call(arguments);mencegah optimasi browser JS seperti V8. Detail di sini
Dheeraj Bhaskar
2
1. Rupanya, argumentsdirencanakan akan ditinggalkan demi operator penyebaran . Saya tidak punya sumber untuk ini, tetapi saya mendengarnya di suatu tempat. 2. MDN negara yang menggunakan slicepada argumentsoptimasi objek mencegah di mesin seperti V8. Mereka menyarankan menggunakan "konstruktor Array yang dihina" Array.from(arguments),, atau [...arguments]. Apakah Anda ingin memperbarui jawaban Anda untuk ES2015?
Braden Best
NB: Saya teruskan dan menulis jawaban saya sendiri .
Braden Best
75

Anda benar-benar dapat memberikan nilai sebanyak yang Anda inginkan ke fungsi javascript apa pun. Parameter yang dinamai secara eksplisit akan mendapatkan beberapa nilai pertama, tetapi SEMUA parameter akan disimpan dalam array argumen.

Untuk meneruskan array argumen dalam bentuk "tidak terbungkus", Anda dapat menggunakan apply, seperti: (cf Javascript Fungsional ):

var otherFunc = function() {
   alert(arguments.length); // Outputs: 10
}

var myFunc = function() {
  alert(arguments.length); // Outputs: 10
  otherFunc.apply(this, arguments);
}
myFunc(1,2,3,4,5,6,7,8,9,10);
danben
sumber
23

Operator percikan dan spread adalah bagian dari ES6, versi Javascript yang direncanakan berikutnya. Sejauh ini hanya Firefox yang mendukung mereka. Kode ini berfungsi di FF16 +:

var arr = ['quick', 'brown', 'lazy'];

var sprintf = function(str, ...args)
{
    for (arg of args) {
        str = str.replace(/%s/, arg);
    }
    return str;
}

sprintf.apply(null, ['The %s %s fox jumps over the %s dog.', ...arr]);
sprintf('The %s %s fox jumps over the %s dog.', 'slow', 'red', 'sleeping');

Perhatikan sintaks awkard untuk spread. Sintaks biasa sprintf('The %s %s fox jumps over the %s dog.', ...arr);yang belum didukung . Anda dapat menemukan tabel kompatibilitas ES6 di sini .

Perhatikan juga penggunaan for...of, tambahan ES6 lainnya. Menggunakan for...inuntuk array adalah ide yang buruk .

Tgr
sumber
Sintaks normal untuk spread sekarang didukung di Firefox dan Chrome
pengguna
8

The applyFungsi membutuhkan dua argumen; objek thisakan diikat, dan argumen, diwakili dengan array.

some_func = function (a, b) { return b }
some_func.apply(obj, ["arguments", "are", "here"])
// "are"
Lilleaas Agustus
sumber
8

Ada dua metode pada ES2015.

The argumentsObject

Objek ini dibangun ke dalam fungsi-fungsi, dan itu merujuk pada, dengan tepat, argumen dari suatu fungsi. Secara teknis ini bukan array, jadi operasi array tipikal tidak akan bekerja di dalamnya. Metode yang disarankan adalah menggunakan Array.fromatau operator spread untuk membuat array darinya.

Saya telah melihat jawaban lain yang disebutkan menggunakan slice. Jangan lakukan itu. Ini mencegah optimasi (sumber: MDN ).

Array.from(arguments)
[...arguments]

Namun, saya berpendapat itu argumentsbermasalah karena menyembunyikan apa fungsi menerima sebagai input. Suatu argumentsfungsi biasanya ditulis seperti ini:

function mean(){
    let args = [...arguments];
    return args.reduce((a,b)=>a+b) / args.length;
}

Kadang-kadang, header fungsi ditulis seperti berikut untuk mendokumentasikan argumen dengan gaya C-like:

function mean(/* ... */){ ... }

Tapi itu jarang terjadi.

Adapun mengapa itu bermasalah, ambil C, misalnya. C kompatibel dengan dialek pra-ANSI kuno dari bahasa yang dikenal sebagai K&R C. K&R C memungkinkan prototipe fungsi memiliki daftar argumen kosong.

int myFunction();
/* This function accepts unspecified parameters */

ANSI C menyediakan fasilitas untuk varargs( ...), dan voiduntuk menentukan daftar argumen kosong.

int myFunction(void);
/* This function accepts no parameters */

Banyak orang secara tidak sengaja menyatakan fungsi dengan unspecifieddaftar argumen ( int myfunction();), ketika mereka mengharapkan fungsi untuk mengambil argumen nol. Secara teknis ini adalah bug karena fungsinya akan menerima argumen. Jumlah mereka.

varargsFungsi yang tepat dalam C berbentuk:

int myFunction(int nargs, ...);

Dan JavaScript sebenarnya memiliki sesuatu yang mirip dengan ini.

Sebarkan Parameter Operator / Istirahat

Saya sudah menunjukkan kepada Anda operator spread, sebenarnya.

...name

Ini cukup serbaguna, dan juga dapat digunakan dalam daftar argumen fungsi ("parameter rest") untuk menentukan vararg dengan cara yang terdokumentasi dengan baik:

function mean(...args){
    return args.reduce((a,b)=>a+b) / args.length;
}

Atau sebagai ungkapan lambda:

((...args)=>args.reduce((a,b)=>a+b) / args.length)(1,2,3,4,5); // 3

Saya lebih suka operator spread. Itu bersih dan mendokumentasikan diri.

Braden Best
sumber
2
terima kasih atas jawaban yang diperbarui, posting ini sebelum ES 2015 jadi saya senang Anda mengisi opsi yang lebih baru
Fire Crow
5

Ini disebut splatoperator. Anda dapat melakukannya dalam JavaScript menggunakan apply:

var arr = ['a','b','c','d'];
var func = function() {
    // debug 
    console.log(arguments.length);
    console.log(arguments);
}
func('a','b','c','d'); // prints 4 which is what I want, then 'a','b','c','d'
func(arr); // prints 1, then 'Array'
func.apply(null, arr); 
Chandra Patni
sumber
4

Dengan ES6 Anda dapat menggunakan parameter istirahat untuk varagrs. Ini mengambil daftar argumen dan mengubahnya menjadi sebuah array.

function logArgs(...args) {
    console.log(args.length)
    for(let arg of args) {
        console.log(arg)
    }
}
masalah theres.yer.
sumber
2

Ini adalah contoh program untuk menghitung jumlah integer untuk argumen variabel dan array pada integer. Semoga ini membantu.

var CalculateSum = function(){
    calculateSumService.apply( null, arguments );
}

var calculateSumService = function(){
    var sum = 0;

    if( arguments.length === 1){
        var args = arguments[0];

        for(var i = 0;i<args.length; i++){
           sum += args[i]; 
        }
    }else{
        for(var i = 0;i<arguments.length; i++){
           sum += arguments[i]; 
        }        
    }

     alert(sum);

}


//Sample method call

// CalculateSum(10,20,30);         

// CalculateSum([10,20,30,40,50]);

// CalculateSum(10,20);
garis
sumber
1
Beberapa catatan: 1. varmendeklarasikan function scopevariabel. Yang baru letdan constkata kunci (ES 2015) mendeklarasikan block scopevariabel. Namun, sebelum ES 2015, variabel-variabel tersebut seharusnya masih diangkat ke atas fungsi sebagai praktik. 2. istirahat fungsi Anda ketika diberikan 1 nilai integer karena penerimaan yang keliru Anda dari sebuah array sebagai argumen (pertanyaan menanyakan tentang varargs; tidak menerima array sebagai argumen): CalculateSum(6) -> 0. (lanjutan di posting berikutnya)
Braden Best
1
3. Jangan gunakan fungsi debug seperti alert. Sebenarnya, jangan gunakan alert/prompt/confirm, titik. Gunakan console.logsebaliknya saat debugging. 4. Fungsi harus berupa returnnilai, bukan alertnilai. 5. hindari PascalCasekecuali jika mengacu pada "tipe" data. Yaitu sebuah kelas. Gunakan camelCaseatau under_scoresebagai gantinya. 4. Saya tidak suka cara Anda mendeklarasikan fungsi Anda. var f = function(){ ... }menyiratkan bahwa Anda ingin itu berubah di beberapa titik, yang mungkin bukan niat Anda. Gunakan function name(){ ... }sintaksis konvensional sebagai gantinya.
Braden Best
Untuk menunjukkan semua poin kritik ini, berikut adalah versi perbaikan fungsi dalam jawaban Anda.
Braden Best
2
(function(window) {
  var proxied = window.alert;
  window.alert = function() {
    return proxied.apply(window, arguments);
  };
}(this));

alert(13, 37);
yaart
sumber
1

Bagi mereka yang dialihkan ke sini dari Melewati jumlah variabel argumen dari satu fungsi ke fungsi lainnya (yang tidak boleh ditandai sebagai duplikat dari pertanyaan ini):

Jika Anda mencoba meneruskan sejumlah variabel argumen dari satu fungsi ke fungsi lainnya, karena JavaScript 1.8.5 Anda cukup memanggil apply()fungsi kedua dan meneruskan argumentsparameternya:

var caller = function()
{
    callee.apply( null, arguments );
}

var callee = function()
{
    alert( arguments.length );
}

caller( "Hello", "World!", 88 ); // Shows "3".

Catatan: Argumen pertama adalah thisparameter yang digunakan. Passing nullakan memanggil fungsi dari konteks global, yaitu sebagai fungsi global alih-alih metode dari beberapa objek.

Menurut dokumen ini , spesifikasi ECMAScript 5 mendefinisikan ulang apply()metode untuk mengambil "objek mirip array generik", alih-alih hanya sebuah Array. Dengan demikian, Anda bisa langsung meneruskan argumentsdaftar ke fungsi kedua.

Diuji di Chrome 28.0, Safari 6.0.5, dan IE 10. Cobalah dengan JSFiddle ini .

andrewtc
sumber
0

Ya, Anda dapat melewati variabel no. argumen ke suatu fungsi. Anda dapat menggunakannya applyuntuk mencapai ini.

Misalnya:

var arr = ["Hi","How","are","you"];

function applyTest(){
    var arg = arguments.length;
    console.log(arg);
}

applyTest.apply(null,arr);
Abhijit
sumber
0

Apakah Anda ingin fungsi Anda bereaksi terhadap argumen array atau argumen variabel? Jika yang terakhir, coba:

var func = function(...rest) {
  alert(rest.length);

  // In JS, don't use for..in with arrays
  // use for..of that consumes array's pre-defined iterator
  // or a more functional approach
  rest.forEach((v) => console.log(v));
};

Tetapi jika Anda ingin menangani argumen array

var fn = function(arr) {
  alert(arr.length);

  for(var i of arr) {
    console.log(i);
  }
};
Dev Yego
sumber