関数の引数のJavaScript変数数


531

JavaScriptの関数に「無制限」の変数を許可する方法はありますか?

例:

load(var1, var2, var3, var4, var5, etc...)
load(var1)



1
@ルークいいえ、そうではありません。その質問は、配列内の引数を使用して、任意の数の引数を持つ関数を呼び出す方法を尋ねます。これは、そのような呼び出しを処理する方法を尋ねます。
だらしない

1
検索を簡単にするために、このような関数は「可変関数」と呼ばれます。
gschenk

回答:


814

もちろん、argumentsオブジェクトを使用してください。

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

1
Tnx。これは、AndroidネイティブコードからWebviewのJavaScriptへの文字列の解析に最適です。
Johan Hoeksma 2013

4
このソリューションは私にとって最も効果的でした。ありがとう。引数キーワードの詳細については、こちらをご覧ください。
User2 2014

26
arguments特別な「配列のような」オブジェクトです。つまり、オブジェクトには長さがありますが、他の配列関数はありません。詳細およびこの回答については、developer.mozilla.org / en-US
Luke

4
興味深いことに、JavaScriptのArrayメソッドは、lengthプロパティを持つ任意のオブジェクトで機能するように定義されています。これにはargumentsオブジェクトが含まれます。これと、メソッドconcatが呼び出された「配列」のコピーを返すことを知っていれば、次のargumentsようにオブジェクトを実際の配列に簡単に変換できますvar args = [].concat.call(arguments)Array.prototype.concat.call代わりに使用することを好む人もいますが、私はが好きで[]、短くて甘いです!
Stijn de Witt

2
@YasirJanの使用[...arguments].join()
Willian D. Andrade

179

(ほとんどの)最近のブラウザーでは、次の構文で可変数の引数を受け入れることができます。

function my_log(...args) {
     // args is an Array
     console.log(args);
     // You can pass this array as parameters to another function
     console.log(...args);
}

ここに小さな例があります:

function foo(x, ...args) {
  console.log(x, args, ...args, arguments);
}

foo('a', 'b', 'c', z='d')

=>

a
Array(3) [ "b", "c", "d" ]
b c d
Arguments
    0: "a"
    1: "b"
    2: "c"
    3: "d"
    length: 4

ドキュメントとその他の例:https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters


27
FYIは「残りのパラメータの構文」と呼ばれている:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
tanguy_k

4
+1これはエレガントでクリーンなソリューションです。パラメータの長いリストを別の関数呼び出しに渡す場合、およびそれらの可変パラメータが任意の位置にある可能性がある場合に特に適しています。
haxpor 2017

3
developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…によれば、IEではサポートされていないことに注意してください。
Roee Gavirel、2018

2
ブラウザのサポートを示す表は次のとおりです-caniuse.com/#feat=rest-parameters
Brian Burns

1
そのような素晴らしい答え!
アシッシュ

113

別のオプションは、コンテキストオブジェクトで引数を渡すことです。

function load(context)
{
    // do whatever with context.name, context.address, etc
}

このように使用します

load({name:'Ken',address:'secret',unused:true})

これには、名前付き引数をいくつでも追加できるという利点があり、関数は必要に応じてそれらを使用する(または使用しない)ことができます。


4
これは、引数の順序への結合を取り除くので、より良いでしょう。疎結合のインターフェースは標準的な習慣として適しています...
Jonas Schubert Erlandsson 2013年

9
確かに、それはいくつかのケースでより良いです。しかし、個々の引数が実際には相互に関連していない、またはすべてが等しい意味を持っているとしましょう(配列要素のように)。それからOPの方法が最善です。
rvighne 2013

1
必要に応じて、contextコードを使用して引数を作成し、使用する前に渡すことができるので、これも便利です。
Nate CK

46

私はケンの答えが最もダイナミックであることに同意し、さらに一歩進めたいと思います。異なる引数で複数回呼び出す関数の場合-私はケンのデザインを使用しますが、次にデフォルト値を追加します。

function load(context) {

    var defaults = {
        parameter1: defaultValue1,
        parameter2: defaultValue2,
        ...
    };

    var context = extend(defaults, context);

    // do stuff
}

このように、多くのパラメーターがあり、関数を呼び出すたびにパラメーターを設定する必要がない場合は、単にデフォルト以外を指定できます。拡張メソッドについては、jQueryの拡張メソッド($.extend())を使用するか、独自に作成するか、以下を使用できます。

function extend() {
    for (var i = 1; i < arguments.length; i++)
        for (var key in arguments[i])
            if (arguments[i].hasOwnProperty(key))
                arguments[0][key] = arguments[i][key];
    return arguments[0];
}

これにより、コンテキストオブジェクトがデフォルトとマージされ、オブジェクトの未定義の値がデフォルトで入力されます。


3
+1。素敵なトリック。多くのボイラープレートを保存して、すべてのパラメーターを定義します(デフォルトまたはそれ以外)。
ニール

1
Underscoreの _.defaults()メソッドは、指定された引数とデフォルトの引数をマージする非常に優れた方法です。
mbeasley 2013

18

はい、このように:

function load()
{
  var var0 = arguments[0];
  var var1 = arguments[1];
}

load(1,2);

18

Ramastが指摘したように、残りのパラメーター構文を使用することをお勧めします。

function (a, b, ...args) {}

... args引数の素敵なプロパティを追加したいだけです

  1. これは配列であり、引数のようなオブジェクトではありません。これにより、マップやソートなどの機能を直接適用できます。
  2. すべてのパラメーターが含まれているわけではなく、そこから渡されたパラメーターのみが含まれています。たとえば、この場合の関数(a、b、... args)には、args.lengthに対する引数3が含まれます。

15

すでに述べたように、 argumentsオブジェクトを使用して、可変数の関数パラメーターを取得ます。

同じ引数で別の関数を呼び出す場合は、を使用しますapplyarguments配列に変換することで、引数を追加または削除することもできます。たとえば、次の関数はコンソールにログインする前にテキストを挿入します。

log() {
    let args = Array.prototype.slice.call(arguments);
    args = ['MyObjectName', this.id_].concat(args);
    console.log.apply(console, args);
}

引数を配列に変換するための素晴らしい解決策。今日は役に立ちました。
Dmytro Medvid 2016

8

名前付き引数のアプローチは有用で柔軟であることに一般的に同意しますが(順序を気にしない限り、引数が最も簡単です)、mbeasleyアプローチのコスト(デフォルトと拡張を使用)について懸念があります。これは、デフォルト値を取得するためにかかる非常に大きなコストです。最初に、デフォルトは関数内で定義されるため、すべての呼び出しでデフォルトが再設定されます。次に、||を使用すると、名前付きの値を簡単に読み取って、デフォルトを同時に設定できます。この情報を取得するために、別の新しいオブジェクトを作成してマージする必要はありません。

function load(context) {
   var parameter1 = context.parameter1 || defaultValue1,
       parameter2 = context.parameter2 || defaultValue2;

   // do stuff
}

これは、ほぼ同じ量のコードです(多分少し多いかもしれません)が、実行時コストのほんの一部です。


同意しますが、害は値のタイプまたはデフォルト自体に依存します。それ以外の場合、(parameter1=context.parameter1)===undefined && (parameter1=defaultValue1)またはコード量を減らすには、次のような小さなヘルパー関数function def(providedValue, default) {return providedValue !== undefined ? providedValue : defaultValue;} var parameter1 = def(context.parameter1, defaultValue1)を使用します。ただし、私の主張はまだ残っています。すべての関数呼び出し用に追加のオブジェクト作成し、いくつかのデフォルト値を設定するために高価なループを実行すると、非常に大きなオーバーヘッドになります。
mcurland 2014

7

@roufamaticはargumentsキーワードの使用を示し、@ Kenは使用法のオブジェクトの優れた例を示しましたが、私はこのインスタンスで何が起こっているかについて真に対処しておらず、将来の読者を混乱させたり、関数を明示的に述べていないので悪い習慣を植え付けたりする可能性があります/メソッドは、可変量の引数/パラメーターを取ることを目的としています。

function varyArg () {
    return arguments[0] + arguments[1];
}

別の開発者があなたのコードを調べているとき、この関数がパラメータを取らないと非常に簡単に想定できます。特にその開発者がargumentsキーワードに精通していない場合。このため、スタイルガイドラインに従って一貫性を保つことをお勧めします。すべての例でGoogleを使用します。

同じ関数に可変パラメーターがあることを明示的に述べましょう:

function varyArg (var_args) {
    return arguments[0] + arguments[1];
}

オブジェクトパラメータVS var_args

データマップの唯一の承認および検討されたベストプラクティスメソッドであるため、オブジェクトが必要になる場合があります。連想配列は眉をひそめ、推奨されません。

サイドノート: argumentsキーワードは、実際には数字をキーとして使用してオブジェクトを返します。プロトタイプの継承もオブジェクトファミリです。JSでの適切な配列の使用については、回答の最後を参照してください

この場合、これも明示的に述べることができます。注:この命名規則はGoogleでは提供していませんが、パラメーターの型の明示的な宣言の例です。これは、コードでより厳密な型付きパターンを作成する場合に重要です。

function varyArg (args_obj) {
    return args_obj.name+" "+args_obj.weight;
}
varyArg({name: "Brian", weight: 150});

どれを選ぶ?

これは、関数およびプログラムのニーズによって異なります。たとえば、渡されたすべての引数にわたって反復プロセスに基づいて値を返すことを単に望んでいる場合、ほとんどの場合引数キーワードを使用します。引数の定義とデータのマッピングが必要な場合は、オブジェクトメソッドが適しています。2つの例を見てみましょう。それで完了です。

引数の使用

function sumOfAll (var_args) {
    return arguments.reduce(function(a, b) {
        return a + b;
    }, 0);
}
sumOfAll(1,2,3); // returns 6

オブジェクトの使用法

function myObjArgs(args_obj) {
    // MAKE SURE ARGUMENT IS AN OBJECT OR ELSE RETURN
    if (typeof args_obj !== "object") {
        return "Arguments passed must be in object form!";
    }

    return "Hello "+args_obj.name+" I see you're "+args_obj.age+" years old.";
}
myObjArgs({name: "Brian", age: 31}); // returns 'Hello Brian I see you're 31 years old

オブジェクトの代わりに配列にアクセスする( "... args"残りのパラメーター)

回答の上で述べたように、argumentsキーワードは実際にはオブジェクトを返します。このため、配列に使用するすべてのメソッドを呼び出す必要があります。この例:

Array.prototype.map.call(arguments, function (val, idx, arr) {});

これを回避するには、restパラメーターを使用します。

function varyArgArr (...var_args) {
    return var_args.sort();
}
varyArgArr(5,1,3); // returns 1, 3, 5


3

ケンが提案したように名前付きプロパティを持つオブジェクトを渡すと、すべての呼び出しに一時オブジェクトを割り当てて解放するコストが増えることに注意してください。通常の引数を値または参照で渡すことは、一般的に最も効率的です。多くのアプリケーションではパフォーマンスはそれほど重要ではありませんが、重要なアプリケーションもあります。

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