関数の引数のJavaScript変数数

2010-01-27 javascript function arguments argument-passing

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

例:

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

Answers

もちろん、 argumentsオブジェクトを使用するだけです。

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

関数内でargumentsオブジェクトを使用して、渡されたすべての引数にアクセスできます。

はい、このように:

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

load(1,2);

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

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

このように使用します

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

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

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

function load(context) {

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

    var context = extend(defaults, context);

    // do stuff
}

このように、多くのパラメーターがあり、関数を呼び出すたびにパラメーターを設定する必要がない場合は、単にデフォルト以外を指定できます。 extendメソッドについては、jQueryのextendメソッド( $.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];
}

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

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

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

   // do stuff
}

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

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

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

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

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

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

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

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

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

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

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

@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では提供していませんが、paramの型の明示的な宣言の例です。これは、コードでより厳密な型付きパターンを作成する場合に重要です。

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

Related