256

引数が JavaScript 関数に渡されたかどうかを判断するための 2 つのメソッドを見てきました。ある方法が他の方法よりも優れているのか、それとも使い方が悪いだけなのか疑問に思っています。

 function Test(argument1, argument2) {
      if (Test.arguments.length == 1) argument2 = 'blah';

      alert(argument2);
 }

 Test('test');

または

 function Test(argument1, argument2) {
      argument2 = argument2 || 'blah';

      alert(argument2);
 }

 Test('test');

私が知る限り、どちらも同じ結果になりますが、以前は最初のものしか本番環境で使用していませんでした。

トムが言及した別のオプション:

function Test(argument1, argument2) {
    if(argument2 === null) {
        argument2 = 'blah';
    }

    alert(argument2);
}

Juan のコメントによると、Tom の提案を次のように変更することをお勧めします。

function Test(argument1, argument2) {
    if(argument2 === undefined) {
        argument2 = 'blah';
    }

    alert(argument2);
}
4

14 に答える 14

290

引数が関数に渡されたかどうかを確認するには、いくつかの方法があります。(元の)質問で言及した2つに加えてarguments.length、演算子をチェックまたは使用して||デフォルト値を提供することに加えて、 undefinedviaの引数を明示的にチェックすることも、パラノイドである場合(コメントを参照)argument2 === undefinedtypeof argument2 === 'undefined'

演算子を使用することは標準的な方法になりました - すべてのクールな子供たちがそれを行います||- しかし注意してください: 引数が に評価される場合、デフォルト値falseundefinedトリガーされます。nullfalse0''Boolean(...)false

したがって、問題は、どのチェックをいつ使用するかです。それらはすべてわずかに異なる結果をもたらすためです。

チェックarguments.lengthは「最も正しい」動作を示しますが、オプションの引数が複数ある場合は実行できない場合があります。

のテストundefinedは次の「最良」です。関数が値で明示的に呼び出された場合にのみ「失敗」しundefinedます。これは、おそらく引数を省略するのと同じ方法で処理する必要があります。

有効な引数が指定されている場合でも、||演算子を使用すると、デフォルト値が使用される可能性があります。一方、その動作は実際には望ましい場合があります。

要約すると、自分が何をしているのかわかっている場合にのみ使用してください。

私の意見で||は、複数のオプションの引数があり、名前付きパラメーターの回避策としてオブジェクト リテラルを渡したくない場合にも、使用する方法があります。

を使用してデフォルト値を提供する別の良い方法arguments.lengthは、switch ステートメントのラベルを通過することによって可能です。

function test(requiredArg, optionalArg1, optionalArg2, optionalArg3) {
    switch(arguments.length) {
        case 1: optionalArg1 = 'default1';
        case 2: optionalArg2 = 'default2';
        case 3: optionalArg3 = 'default3';
        case 4: break;
        default: throw new Error('illegal argument count')
    }
    // do stuff
}

これには、プログラマーの意図が (視覚的に) 明白ではなく、「マジック ナンバー」を使用するという欠点があります。したがって、エラーが発生しやすい可能性があります。

于 2009-01-04T17:46:09.197 に答える
18

jQuery を使用している場合、(特に複雑な状況で) 便利なオプションの 1 つは、jQuery の extends メソッドを使用することです。

function foo(options) {

    default_options = {
        timeout : 1000,
        callback : function(){},
        some_number : 50,
        some_text : "hello world"
    };

    options = $.extend({}, default_options, options);
}

関数を呼び出すと、次のようになります。

foo({timeout : 500});

options 変数は次のようになります。

{
    timeout : 500,
    callback : function(){},
    some_number : 50,
    some_text : "hello world"
};
于 2013-04-30T18:16:37.493 に答える
16

これは、テストを見つける数少ないケースの 1 つです。

if(! argument2) {  

}

非常にうまく機能し、構文的に正しい意味を持ちます。

argument2(他の意味を持つ正当なnull値を許可しないという同時制限がありますが、それは本当に混乱するでしょう。)

編集:

これは、緩く型付けされた言語と強く型付けされた言語のスタイルの違いを示す非常に良い例です。そして、javascript がスペードで提供する文体オプション。

私の個人的な好み (他の好みを批判するものではありません) は、ミニマリズムです。私が一貫して簡潔である限り、コードの内容が少なければ少ないほど、他の誰かが私の意味を正しく推測するために理解する必要が少なくなります。

その好みの1つの含意は、私が望んでいないということです-それが有用だとは思いません-たくさんの型依存性テストを積み上げます。代わりに、コードが意味するように見えるようにしようとします。本当にテストする必要があるものだけをテストします。

他の人々のコードで私が見つけた悪化の 1 つは、より大きなコンテキストで、彼らがテストしているケースに実際に遭遇することを期待しているかどうかを把握する必要があることです。または、可能な限りすべてをテストしようとしている場合は、コンテキストを完全に予測していない可能性があります。つまり、自信を持って何かをリファクタリングまたは変更する前に、それらを双方向で徹底的に追跡する必要があります。彼らが必要となる状況を予見していたので(そして、それは通常私には明らかではありませんでした)、彼らがこれらのさまざまなテストを実施した可能性が高いと思います。

(私は、これらの人々が動的言語を使用する方法の深刻な欠点だと考えています。あまりにも多くの場合、人々はすべての静的テストを放棄したくなく、それを偽造してしまいます。)

これは、包括的な ActionScript 3 コードと洗練された JavaScript コードを比較したときに最も顕著にわかりました。AS3 は js の 3 倍または 4 倍の大きさになる可能性があり、コーディングの決定が行われた回数 (3 倍から 4 倍) のために、信頼性は少なくとも良くないと思います。

おっしゃるとおり、Shog9、YMMV。:D

于 2009-01-04T17:53:23.830 に答える
7

大きな違いがあります。いくつかのテストケースを設定しましょう:

var unused; // value will be undefined
Test("test1", "some value");
Test("test2");
Test("test3", unused);
Test("test4", null);
Test("test5", 0);
Test("test6", "");

説明した最初の方法では、2 番目のテストのみがデフォルト値を使用します。2 番目のメソッドは、最初のメソッドを除くすべてをデフォルトに設定します (JS がundefined, null, 0, を""boolean に変換するためfalseです。Tom のメソッドを使用する場合、4 番目のテストのみがデフォルトを使用します!

どちらの方法を選択するかは、意図する動作によって異なります。以外の値undefinedが に許容されるargument2場合は、おそらく最初の値にいくつかのバリエーションが必要になるでしょう。0 以外、null 以外、空でない値が必要な場合は、2 番目の方法が理想的です。実際、このような広い範囲の値を考慮からすばやく除外するためによく使用されます。

于 2009-01-04T17:57:44.197 に答える
7
url = url === undefined ? location.href : url;
于 2012-08-21T09:51:08.540 に答える
4

申し訳ありませんが、まだコメントできないので、トムの答えに答えるために... In javascript (undefined != null) == false 実際、その関数は「null」では機能しません。「undefined」を使用する必要があります。

于 2009-01-04T17:48:14.577 に答える
3

なぜ!!演算子を使用しないのですか? 変数の前に配置されたこの演算子は、それをブール値に変換します (私がよく理解している場合)。そのため!!undefined、 and !!null(および でさえ!!NaN、非常に興味深い場合があります) は を返しfalseます。

次に例を示します。

function foo(bar){
    console.log(!!bar);
}

foo("hey") //=> will log true

foo() //=> will log false
于 2015-12-30T13:01:58.737 に答える
3

パラメータが関数に渡されているかどうかを確認するためのトリッキーな方法もあります。以下の例を見てください。

this.setCurrent = function(value) {
  this.current = value || 0;
};

これは、 の値がvalue存在しない/渡されない場合は、値を 0 に設定する必要があることを意味します。

かっこいいですね!

于 2017-03-24T18:44:49.697 に答える
2

オプションのプロパティのオブジェクトを使用して関数を呼び出して、引数の検出にアプローチすると便利な場合があります。

function foo(options) {
    var config = { // defaults
        list: 'string value',
        of: [a, b, c],
        optional: {x: y},
        objects: function(param){
           // do stuff here
        }
    }; 
    if(options !== undefined){
        for (i in config) {
            if (config.hasOwnProperty(i)){
                if (options[i] !== undefined) { config[i] = options[i]; }
            }
        }
    }
}
于 2013-03-05T02:22:31.240 に答える
1

特に関数を getter および setter として使用している場合は、タイプを確認することもできます。次のコードは ES6 です (EcmaScript 5 以前では実行されません)。

class PrivateTest {
    constructor(aNumber) {
        let _aNumber = aNumber;

        //Privileged setter/getter with access to private _number:
        this.aNumber = function(value) {
            if (value !== undefined && (typeof value === typeof _aNumber)) {
                _aNumber = value;
            }
            else {
                return _aNumber;
            }
        }
    }
}
于 2016-05-18T19:06:28.060 に答える
-1

fnCalledFunction(Param1,Param2, window.YourOptionalParameter)

上記の関数が多くの場所から呼び出され、最初の 2 つのパラメーターがすべての場所から渡されていることは確かですが、3 番目のパラメーターについては不明な場合は、window を使用できます。

window.param3 は、呼び出し元メソッドから定義されていない場合に処理されます。

于 2018-06-28T05:56:06.497 に答える