Bir JavaScript işlevine değişken sayıda bağımsız değişken göndermek mümkün müdür?


171

Bir diziden bir JavaScript işlevine değişken sayıda bağımsız değişken göndermek mümkün müdür?

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'

Son zamanlarda bir sürü Python yazdım ve vararları kabul edip göndermek harika bir model. Örneğin

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'

JavaScript tedavi edilecek bir dizi göndermek mümkün mü olduğu argümanlar diziye?


4
Nesne for - inile bir döngü kullanmak iyi bir fikir değildir arguments- lengthbunun yerine özellik üzerinde yineleme için bir 'normal' kullanılmalıdır
Yi Jiang

2
bu hiç sorun olmadı, neden böyle olduğunu açıklayabilir misin? arguments nesnesi neredeyse her zaman agruments [0..length-1] sürümünü kullanmak için ihmal edilebilir bir performans iyileştirmesine sahip olacak kadar küçüktür.
Ateş Kargası


1
Ben bağımsız değişkenler gerçek bir dizi değil, özel bir nesne olduğunu düşünüyorum, bu yüzden "in" sözdizimi JS uygulamasına bağlı olarak çalışmayabilir.
O'Rooney

Yanıtlar:


209

Güncelleme : ES6'dan beri , işlevi çağırırken forma sözdizimini kullanabilirsiniz :

func(...arr);

ES6 da, bağımsız değişkenlerinize dizi olarak davranmayı düşünüyorsanız, parametre listesindeki forma sözdizimini de kullanabilirsiniz, örneğin:

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

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

Ve normal parametrelerle birleştirebilirsiniz, örneğin ilk iki argümanı ayrı ayrı ve geri kalanını bir dizi olarak almak istiyorsanız:

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

Ve belki bir fonksiyon sizin için yararlıdır, bir fonksiyonun kaç argüman beklediğini bilirsiniz:

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

Ama yine de rastgele sayıda argüman iletebilirsiniz ...

Forma sözdizimi daha kısadır ve "daha tatlı" dır ve işlev çağrısında değeri applyayarlamanız gerekmiyorsa this, bu yoludur.

İşte bunu yapmanın eski yolu olan bir uygulama örneği:

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

Günümüzde sadece applybir diziden isteğe bağlı sayıda argüman geçirmeniz vethis değeri ayarlamanız gerektiğinde kullanmanızı öneririm . applyalır, thisişlev çağırmada kullanılacak ilk bağımsız değişkenler olarak değerdir; nullkatı olmayan bir kodda kullanırsak, thisanahtar kelime funcaçıkça 'use katı' kullanılırken katı modda içindeki Global nesneye (pencere) atıfta bulunur. 'veya ES modüllerinde nullkullanılacaktır.

Ayrıca, argumentsnesnenin gerçekten bir Array olmadığını unutmayın , şu şekilde dönüştürebilirsiniz:

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

Ve ES6'da:

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

Ancak argumentsyayılan sözdizimi sayesinde nesneyi nadiren doğrudan kullanırsınız .


1
Teşekkürler, uygula hile yapar, bu durumda çağrı işe yaramaz. Yanlışlıkla yazılmış mıydı?
Fire Crow

İşlev aslında bir sınıfın üyesiyse bunu nasıl yaparsınız? Bu doğru mu? theObject.member.apply (theObject, bağımsız değişkenler);
Baxissimo

4
Array.prototype.slice.call(arguments);V8 gibi tarayıcı JS optimizasyonlarını önler. Ayrıntılar burada
Dheeraj Bhaskar

2
1. Görünüşe göre, spread operatörüarguments lehine itiraz edilmesi planlanıyor . Bunun için bir kaynağım yok, ama bir yerde duydum. 2. MDN , nesne üzerinde kullanmanın V8 gibi motorlarda optimizasyonları önlediğini belirtir . Onlar "aşağılık Array yapıcısı" , veya . ES2015 için yanıtınızı güncellemek ister misiniz? sliceargumentsArray.from(arguments)[...arguments]
Braden Best

Not: Devam ettim ve kendi cevabımı yazdım .
Braden Best

75

Aslında herhangi bir javascript işlevine istediğiniz kadar değer iletebilirsiniz. Açıkça adlandırılmış parametreler ilk birkaç değeri alır, ancak TÜM parametreler arguments dizisinde saklanır.

Arguments dizisini "paketlenmemiş" biçimde iletmek için, uygula seçeneğini kullanabilirsiniz (cf Functional Javascript ):

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

23

Uyarısı ve yayılma operatörleri ES6, Javascript planlanan bir sonraki sürümü parçasıdır. Şimdiye kadar sadece Firefox onları destekliyor. Bu kod FF16 + 'da çalışır:

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

Yayılma için awkard sözdizimine dikkat edin. Olağan sözdizimi sprintf('The %s %s fox jumps over the %s dog.', ...arr);olduğunu henüz desteklenmemektedir . Sen bulabilirsiniz burada ES6 uyumluluk tablosu .

Ayrıca for...of, başka bir ES6 ekinin kullanımına dikkat edin. for...inDiziler için kullanmak kötü bir fikirdir .


Yayılma için normal sözdizimi artık Firefox ve Chrome'da destekleniyor
kullanıcı

8

applyİşlev, iki bağımsız değişken; nesne thisbağlanacak ve argümanlar bir dizi ile temsil edilecektir.

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

8

ES2015'ten itibaren iki yöntem vardır.

argumentsNesne

Bu nesne fonksiyonlar içine yerleştirilmiştir ve uygun şekilde bir fonksiyonun argümanlarını ifade eder. Bununla birlikte, teknik olarak bir dizi değildir, bu nedenle tipik dizi işlemleri üzerinde çalışmaz. Önerilen yöntem, Array.frombir dizi oluşturmak için forma operatörünü kullanmaktır .

Kullandığım diğer cevapları gördüm slice. Bunu yapma. Optimizasyonları önler (kaynak: MDN ).

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

Ancak argumentsbunun problemli olduğunu savunurum çünkü bir fonksiyonun girdi olarak kabul ettiği şeyi gizler. Bir argumentsişlev genellikle şu şekilde yazılır:

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

Bazen, işlev başlığı, C benzeri bir şekilde argümanları belgelemek için aşağıdaki gibi yazılır:

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

Ancak bu nadirdir.

Neden sorunlu olduğuna gelince, örneğin C'yi ele alalım. C, K&R C olarak bilinen dilin eski bir ANSI öncesi lehçesi ile geriye dönük olarak uyumludur. K&R C, fonksiyon prototiplerinin boş bir argüman listesine sahip olmasını sağlar.

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

ANSI C, varargs( ...) için bir olanak sağlar ve voidboş bir bağımsız değişkenler listesi belirtir.

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

Birçok kişi , işlevin sıfır bağımsız değişken almasını beklediklerinde yanlışlıkla unspecifiedargüman listesi ( int myfunction();) ile işlevleri bildirir. Fonksiyon, çünkü bu teknik olarak bir hata olduğunu edecektir argümanları kabul ediyoruz. Herhangi bir sayıda.

varargsC'deki uygun bir işlev şu şekildedir:

int myFunction(int nargs, ...);

Ve JavaScript'in aslında buna benzer bir şeyi var.

Forma Operatörü / Dinlenme Parametreleri

Aslında zaten yayılmış operatörü gösterdim.

...name

Oldukça çok yönlüdür ve varargs'ı iyi belgelenmiş bir şekilde belirtmek için bir işlevin bağımsız değişken listesinde ("dinlenme parametreleri") de kullanılabilir:

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

Veya lambda ifadesi olarak:

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

Forma operatörünü çok tercih ederim. Temiz ve kendi kendini belgelendirir.


2
güncellenen cevap için teşekkür ederim, bu yazı ES 2015'ten önce gelir, bu yüzden daha yeni seçenekleri doldurduğunuza sevindim
Fire Crow

5

Buna splatoperatör denir . JavaScript kullanarak şunları yapabilirsiniz 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); 

4

ES6 ile kullanabilirsiniz dinlenme parametreleri için varagrs. Bu, argüman listesini alır ve bir diziye dönüştürür.

function logArgs(...args) {
    console.log(args.length)
    for(let arg of args) {
        console.log(arg)
    }
}

2

Bu, değişken argümanları için tamsayıların toplamı ve tamsayılar üzerinde dizi hesaplamak için örnek bir programdır. Bu yardımcı olur umarım.

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

1
Bazı notlar: 1. varbir function scopedeğişken bildirir . Yeni letve constanahtar kelimeler (ES 2015) block scopedeğişkenleri bildirir. Yine de ES 2015'ten önce, değişkenler hala bir uygulama meselesi olarak işlevin üst kısmına kaldırılmış olmalıdır. 2. için bir bağımsız değişken olarak bir dizi için hatalı kabul 1 tam sayı değer verilir, işlev sonları (soru ile ilgili varargs sorar, bağımsız değişkenler olarak diziler kabul değil): CalculateSum(6) -> 0. (sonraki yazıda devam etti)
Braden Best

1
3. gibi hata ayıklama fonksiyonları kullanmayın alert. Aslında, sadece kullanma alert/prompt/confirm, nokta. console.logHata ayıklama sırasında bunun yerine kullanın . 4. Fonksiyon returnbir değer değil alert, değil olmalıdır. 5. PascalCase"veri" türüne değinmediği sürece kaçının . Yani bir sınıf. Kullanın camelCaseveya under_scorebunun yerine. 4. İşlevlerinizi beyan etme şeklinizi sevmiyorum. var f = function(){ ... }bir noktada değişmesini istediğinizi ima eder , ki bu muhtemelen sizin niyetiniz değildir. function name(){ ... }Bunun yerine geleneksel sözdizimini kullanın.
Braden Best

Tüm bu eleştiri noktalarını göstermek için, cevabınızdaki fonksiyonun geliştirilmiş bir versiyonu .
Braden Best

2
(function(window) {
  var proxied = window.alert;
  window.alert = function() {
    return proxied.apply(window, arguments);
  };
}(this));

alert(13, 37);

1

Buraya yönlendirildiniz olanlar için başka bir işlevinden bağımsız değişken sayısı Geçme (ki gerektiği değil bu soruya tekrarı olarak işaretlenecektir):

Bir işlevden diğerine değişken sayıda bağımsız değişken aktarmaya çalışıyorsanız, JavaScript 1.8.5'ten bu yana apply()ikinci işlevi çağırabilir ve argumentsparametreyi iletebilirsiniz :

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

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

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

Not: İlk argüman kullanılacak thisparametredir. Passing null, işlevi genel bağlamdan, yani bazı nesnelerin yöntemi yerine global bir işlev olarak çağırır.

Bu belgeye göre , ECMAScript 5 spesifikasyonu apply(), kesinlikle bir Array yerine herhangi bir "jenerik dizi benzeri nesne" alma yöntemini yeniden tanımladı . Böylece, argumentslisteyi doğrudan ikinci işleve geçirebilirsiniz .

Chrome 28.0, Safari 6.0.5 ve IE 10'da test edilmiştir. Bu JSFiddle ile deneyin .


0

Evet, hayır değişkenini iletebilirsiniz. bir işleve bağımsız değişkenler. Bunu applybaşarmak için kullanabilirsiniz .

Örneğin:

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

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

applyTest.apply(null,arr);

0

İşlevinizin bir dizi bağımsız değişkenine veya değişken bağımsız değişkenlerine tepki vermesini istiyor musunuz? İkincisi ise deneyin:

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

Ancak bir dizi argümanını ele almak istiyorsanız

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

  for(var i of arr) {
    console.log(i);
  }
};
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.