JavaScript関数に可変数の引数を送信することは可能ですか?


171

配列から可変数の引数をJavaScript関数に送信することは可能ですか?

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'

私は最近多くのPythonを作成しましたが、可変引数を受け入れて送信できるのは素晴らしいパターンです。例えば

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で引数配列として扱われる配列を送信することは可能ですか?


4
オブジェクトでfor - inループを使用するのは良い考えではないことに注意してください。代わりにargumentslengthプロパティを反復する「通常」のforループを使用する必要があります
Yi Jiang

2
それは決して問題ではありませんでした、なぜそれが事実であるかについて詳しく説明できますか?argumentsオブジェクトは、ほとんどの場合、agruments [0..length-1]バージョンを使用した場合のパフォーマンスの向上が無視できるほど小さいです。
Fire Crow


1
引数は実際の配列ではなく特別なオブジェクトであるため、JSの実装によっては「in」構文が機能しない可能性があると思います。
オルーニー

回答:


209

更新:ES6以降、関数を呼び出すときにスプレッド構文を使用できます。

func(...arr);

ES6では引数を配列として扱うことが予想される場合もあるので、パラメーターリストでスプレッド構文を使用することもできます。次に例を示します。

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

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

そして、たとえば最初の2つの引数を個別に受け取り、残りを配列として受け取りたい場合は、それを通常のパラメーターと組み合わせることができます。

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

そして、おそらくあなたにとって便利です、あなたは関数が期待する引数の数を知ることができるということです:

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

しかし、とにかく、任意の数の引数を渡すことができます...

スプレッドの構文は、より短くて「甘い」ので、関数呼び出しで値applyを設定する必要がない場合thisは、この方法が適しています。

ここで適用され、例えば、それを行うには、元の方法でした。

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

今日ではapply、配列から任意の数の引数を渡して値設定する必要がある場合のみ使用することをお勧めしthisます。applytakeはthis最初の引数としての値であり、関数の呼び出しで使用されます。null厳密でないコードで使用する場合、thisキーワードはfunc、明示的に 'use strict 'またはESモジュールでnullは、使用されます。

また、argumentsオブジェクトは実際には配列ではないことに注意してください。次の方法で変換できます。

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

そしてES6では:

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

ただしarguments、spread構文のおかげで、最近ではオブジェクトを直接使用することはほとんどありません。


1
おかげで、適用はトリックを行います、この場合の呼び出しは機能しません。それは間違って書かれたのですか?
Fire Crow、

関数が実際にクラスのメンバーである場合はどうすればよいですか?これは正解?theObject.member.apply(theObject、arguments);
Baxissimo

4
Array.prototype.slice.call(arguments);V8のようなブラウザのJS最適化を防ぎます。詳細はこちら
Dheeraj Bhaskar 2014

2
1.どうやら、スプレッドオペレーターのargumentsために廃止される予定です。情報源はありませんが、どこかで聞いたことがあります。2. MDNは、オブジェクトでの使用がV8などのエンジンでの最適化を妨げると述べています。彼らは、「despised Arrayコンストラクタ」、、またはを使用することを提案しています。ES2015の回答を更新しますか? sliceargumentsArray.from(arguments)[...arguments]
ブレーデンベスト

注意:私は先に進んで自分の答えを書きました。
ブレーデンベスト

75

実際には、JavaScript関数に必要な数の値を渡すことができます。明示的に名前が付けられたパラメーターは最初のいくつかの値を取得しますが、すべてのパラメーターは引数配列に格納されます。

引数の配列を「アンパック」形式で渡すには、applyを次のように使用できます(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

スプラット普及事業者はES6は、JavaScriptの計画次のバージョンの一部です。これまでのところ、Firefoxのみがそれらをサポートしています。このコードは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');

スプレッドのawkard構文に注意してください。の通常の構文sprintf('The %s %s fox jumps over the %s dog.', ...arr);まだサポートされていません。あなたは見つけることができ、ここでES6適合表を

for...ofES6の追加機能であるの使用にも注意してください。for...in配列の使用は悪い考えです。


スプレッドの通常の構文がFirefoxとChromeでサポートされるようになりました
ユーザーの

8

このapply関数は2つの引数を取ります。オブジェクトthisはバインドされ、引数は配列で表されます。

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

8

ES2015現在、2つの方法があります。

argumentsオブジェクト

このオブジェクトは関数に組み込まれており、適切に関数の引数を参照します。ただし、技術的には配列ではないため、一般的な配列操作では機能しません。推奨される方法は、Array.fromまたはスプレッド演算子を使用して、そこから配列を作成することです。

他の回答がを使用して言及するのを見ましたslice。しないでください。最適化を防ぎます(ソース:MDN)。

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

ただし、arguments関数が入力として受け入れるものを隠すため、これは問題があると主張します。arguments機能は、典型的には、このように書かれています:

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

関数のヘッダーは、Cのような方法で引数を文書化するために、次のように記述されることがあります。

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

しかし、それはまれです。

なぜそれが問題であるかについては、例えばCを取ってください。Cは、K&R Cと呼ばれる言語の古代ANSI方言と下位互換性があります。K&R Cでは、関数プロトタイプに空の引数リストを含めることができます。

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

ANSI Cはvarargs...)の機能を提供しvoid、空の引数リストを指定します。

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

多くの人々は、関数が引数をとらないことを期待しているときに、unspecified引数リスト(int myfunction();)を使用して関数を誤って宣言します。関数引数受け入れるため、これは技術的にバグです。それらの任意の数。

varargsCの適切な関数は次の形式を取ります。

int myFunction(int nargs, ...);

そして、JavaScriptは実際にこれに似たものを持っています。

スプレッドオペレーター / レストパラメーター

実際、スプレッドオペレーターについてはすでに説明しました。

...name

これはかなり用途が広く、関数の引数リスト(「残りのパラメーター」)で使用して、適切に文書化された方法で可変引数を指定できます。

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

またはラムダ式として:

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

スプレッドオペレーターの方がずっと好きです。クリーンで自己文書化されています。


2
更新された回答をありがとう、この投稿はES 2015よりも前の日付なので、より最近のオプションを入力してくれてうれしい
Fire Crow

5

それはsplat演算子と呼ばれています。あなたはJavaScriptを使ってそれを行うことができます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では、残りのパラメータを使用できますvaragrs。これは引数リストを取り、それを配列に変換します。

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

2

これは、可変引数の整数の合計と整数の配列を計算するためのサンプルプログラムです。お役に立てれば。

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
注意事項:1 .変数をvar宣言しfunction scopeます。新しいキーワードletconstキーワード(ES 2015)はblock scope変数を宣言します。ただし、ES 2015より前のバージョンでは、変数は実際には関数の最上部まで引き上げられているはずです。2.配列を引数として誤って受け入れるため、1つの整数値を指定すると、関数が壊れます(質問はvarargsについて尋ねます。配列を引数として受け入れません)CalculateSum(6) -> 0。(次の投稿に続く)
Braden Best

1
3.などのデバッグ関数を使用しないでくださいalert。実際にはalert/prompt/confirm、ピリオドは使用しないでください。console.logデバッグ時に代わりに使用します。4.関数はreturn値ではなく、値である必要がありますalert。5. PascalCaseデータの「タイプ」を参照しない限り避けてください。すなわちクラス。camelCaseまたはunder_score代わりに使用します。4.関数の宣言方法が気に入らない。ある時点で変更var f = function(){ ... }たいことを意味しますが、それはおそらくあなたの意図ではありません。代わりに、従来の構文を使用してください。function name(){ ... }
Braden Best

これらすべての批評点を実証するために、ここに回答の関数の改良版を示します。
ブレーデンベスト2017

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

alert(13, 37);

1

ここで、ある関数から別の関数に可変数の引数を渡すことからリダイレクトされた場合(これは、この質問の重複としてマークされるべきでありませ):

ある関数から別の関数に可変数の引数を渡そうとしている場合、JavaScript 1.8.5以降apply()、2番目の関数を呼び出してargumentsパラメーターを渡すだけです。

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

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

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

注:最初の引数は、this使用するパラメーターです。渡すnullと、グローバルコンテキストから関数が呼び出されます。つまり、オブジェクトのメソッドの代わりにグローバル関数として呼び出されます。

このドキュメントによると、ECMAScript 5仕様では、apply()メソッドを再定義して、厳密に配列ではなく、「一般的な配列のようなオブジェクト」を取得します。したがって、argumentsリストを2番目の関数に直接渡すことができます。

Chrome 28.0、Safari 6.0.5、IE 10でテスト済み。このJSFiddleで試してみてください。


0

はい、変数noを渡すことができます。関数への引数の。applyこれを達成するために使用できます。

例えば:

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

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

applyTest.apply(null,arr);

0

関数が配列引数または変数引数に反応するようにしますか?後者の場合は、以下を試してください。

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

しかし、配列引数を処理したい場合

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

  for(var i of arr) {
    console.log(i);
  }
};
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.