引数がJavaScript関数に送信されていないかどうかを判断する最良の方法


236

これで、引数が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');

私の知る限り、どちらも同じ結果になりますが、本番環境では最初の1つだけを使用しました。

トムが述べた別のオプション:

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

    alert(argument2);
}

フアンのコメントに従って、トムの提案を次のように変更することをお勧めします。

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

    alert(argument2);
}

それは本当に同じです。常に静的な数の引数がある場合は、2番目の方法を使用します。そうでない場合は、おそらく引数の配列を使用して反復する方が簡単です。
Luca Matteis、

7
渡されなかった引数は未定義として入ります。nullに対する厳密な等価性を使用したテストは失敗します。undefinedとの厳密な等価を使用する必要があります。
ファンメンデス

19
注意: argument2 || 'blah';場合は「何とか」になりますargument2されfalse、それが定義されていないいないだけであれば(!)。 場合はargument2ブール値であり、関数が渡されfalse、それのために、その行は、にもかかわらず、「何とか」を返しますargument2適切に定義されています
Sandy Gifford 2013

9
@SandyGifford:場合は、同じ問題argument2である0''またはnull
rvighne 2014年

@rvighne本当にそうです。Javascriptのオブジェクトとキャストのユニークな解釈は、一度にすべてが最良で最悪の部分です。
Sandy Gifford

回答:


274

引数が関数に渡されたかどうかを確認する方法はいくつかあります。チェック-あなたは(元)の質問で述べた2に加えて、arguments.lengthまたは使用して||、デフォルト値を提供するために、オペレータを- 1にも明示の引数を確認することができますundefined経由argument2 === undefinedまたはtypeof argument2 === 'undefined'1が偏執的である場合には(コメントを参照してください)。

使用する||演算子を標準的になってきている-すべてのクールな子供たちはそれを行う-しかし、注意してください:デフォルト値がトリガされる引数評価される場合にfalse、それは実際にであるかもしれない手段、undefinednullfalse0''(または他の何かれる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
}

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


42
typeof argument2 === "undefined"を実際に確認してください。誰かが "undefined"を定義している場合に備えてください。
JW。

133
私は通知を追加します-しかし、どのような病気の野郎がそのようなことをしますか?
Christoph

12
undefinedはグローバル空間の変数です。ローカルスコープの変数よりもグローバルスコープの変数を検索する方が遅くなります。しかし、最速で使用することですtypeofをX ===「未定義」
いくつかの

5
面白い。一方、比較===未定義の方が文字列比較よりも速い場合があります。私のテストは、あなたが、正しいことを示しているように見えるけれども:のX ===未定義必要〜1.5倍の時間typeof演算のx ===「未定義」
クリストフ

4
@クリストフ:あなたのコメントを読んだ後、私は周りに尋ねました。巨大な文字列を比較すると、小さな文字列よりも時間がかかるため、文字列の比較が確実に(唯一の)ポインター比較ではないことを証明できました。ただし、2つの巨大な文字列の比較は、連結して構築された場合にのみ本当に遅くなりますが、2番目の文字列を最初の文字列からの割り当てとして作成した場合は非常に速くなります。したがって、おそらくポインタテストとそれに続く文字ごとのテストで機能します。そうです、そうです、私はがらくたでいっぱいでした:)私を啓蒙してくれてありがとう...
ファンメンデス

17

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

function foo(options) {

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

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

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

foo({timeout : 500});

その場合、オプション変数は次のようになります。

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

15

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

if(! argument2) {  

}

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

(同時に制限があるため、argument2他の意味を持つ正当なnull値を許可しませんが、それは本当に混乱します。)

編集:

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

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

この設定の意味するところの1つは、タイプ依存性テストの束を積み上げたくない-役に立たない-ことです。代わりに、コードが意味するように見えるようにコードを作成しようとします。そして、私が本当にテストする必要があるものだけをテストします。

他の一部の人々のコードで私が見つけた悪化の1つは、彼らがより大きな文脈で、彼らがテストしているケースに実際に遭遇すると期待するかどうかを理解する必要があることです。または、可能な限りすべてをテストしようとしている場合は、コンテキストを十分に予測できない可能性があります。つまり、自信を持ってリファクタリングや変更を行う前に、両方向に徹底的に追跡する必要があります。彼らが必要とされる状況を予測しているため(通常は私にはわからない)、彼らがこれらのさまざまなテストを実施した可能性が十分にあると思います。

(私はこれらの人々が動的言語を使用する方法に深刻な欠点があると思います。あまりに多くの人々は静的テストをすべてあきらめたくないし、結局それを偽造することになります。)

これは、包括的なActionScript 3コードをエレガントなJavaScriptコードと比較するときに最も明白に見られました。AS3はjsの大部分の3倍または4倍にすることができます。また、行われたコーディング決定の数(3〜4X)のために、私が疑う信頼性は少なくともこれ以上良くありません。

あなたが言うように、Shog9、YMMV。:D


1
if(!argument2)argument2 = 'default'はargument2 = argument2 ||と同等です 'デフォルト'-2番目のバージョンは視覚的にもっと楽しいと思います...
Christoph

5
そして、私はそれがより冗長で気が散ることに気づきます。個人的な好みだと思います。
dkretz 2009年

4
@le dorfier:空の文字列、0、およびブール値falseの使用も除外されます。
Shog9 2009年

@le dorfier:美学を超えて、1つの重要な違いがあります。後者は実質的に2番目の実行パスを作成し、不注意なメンテナーがデフォルト値の単純な割り当てを超えて動作を追加するように誘惑する可能性があります。もちろんYMMV。
Shog9 2009年

3
parameter2がブール値の場合=== false; または関数{return false;}?
fresko 2016年

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番目のテストのみがデフォルト値を使用します。第二の方法は、すべてが、最初の(JSが変換されますようデフォルト設定されますundefinednull0、および""ブールにfalse。そして、あなたはトムのメソッドを使用した場合、唯一の第四テストはデフォルトを使用します!

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


7
url = url === undefined ? location.href : url;

裸の骨が答えます。いくつかの説明は害にならないでしょう。
ポールルーニー

それは簡潔に言う三項演算子です:urlが未定義(欠落)の場合、url変数をlocation.href(現在のWebページ)に設定します。それ以外の場合、url変数を定義されたurlに設定します。
rmooney

5

ES6(ES2015)では、デフォルトのパラメーターを使用できます

function Test(arg1 = 'Hello', arg2 = 'World!'){
  alert(arg1 + ' ' +arg2);
}

Test('Hello', 'World!'); // Hello World!
Test('Hello'); // Hello World!
Test(); // Hello World!


この答えは非常に興味深いものであり、運用に役立つ可能性があります。それは本当にいませんが答える質問
ユリスBN

私が見るように
-argが

私のポイントは、引数がJavaScript関数に送信されないかどうかを判断するための最善の方法にあなたが答えていないことです。しかし、質問にデフォルトの引数を使用して答えることできます。たとえば、引数に名前を付けて"default value"、値が本当にかどうかを確認します"default value"
Ulysse BN 2017

4

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


1
そして、トムは間違った答えに対して2つの賛成票を獲得しました-これらのコミュニティシステムがどのように機能するかを知るのはいつも素晴らしいことです;)
Christoph

3

!!演算子を使用しないのはなぜですか?変数の前に置かこの演算子、(私はよく理解している場合)ので、boolean型にそれを回す!!undefined!!null(さらには!!NaN、非常に興味深いことができたが、)を返しますfalse

次に例を示します。

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

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

foo() //=> will log false

ブール値のtrue、0、空の文字列では機能しません。たとえば、foo(0); falseをログに記録しますが、foo(1)はtrueをログに記録します
rosell.dk

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

2

ある見つけるトリッキーな方法だけでなく、パラメータが関数に渡されているかどうか、。以下の例を見てください:

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

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

かっこいい!


1
これは実際には「valueと同等の場合はfalse0に設定する」ことを意味します。これは微妙ですが非常に重要な違いです。
チャールズウッド

@CharlesWood値が渡されない/現在の値がfalseのみであることを示す
Mohammed Zameer

1
もちろん、それが関数の要件に適合している場合は。ただし、たとえば、パラメーターがブール値で、trueかつfalseが有効な値であり、パラメーターがまったく渡されない場合(特に、関数に複数のパラメーターがある場合)の3番目の動作が必要になる場合があります。
チャールズウッド

1
D:私は、これはコンピュータサイエンスの巨大な引数で、ちょうど意見の問題になってしまうことを認めなければならない
チャールズ・ウッド

@CharlesWoodパーティーに遅れて申し訳ありません。編集オプションを使用して、回答自体にこれらを追加することをお勧めします
Mohammed Zameer 2018

1

場合によっては、特に関数をゲッターおよびセッターとして使用している場合は、タイプをチェックすることもできます。次のコードは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;
            }
        }
    }
}

0
function example(arg) {
  var argumentID = '0'; //1,2,3,4...whatever
  if (argumentID in arguments === false) {
    console.log(`the argument with id ${argumentID} was not passed to the function`);
  }
}

配列はから継承するためObject.prototype。世界を良くするためにConsiderを検討してください。


-1

fnCalledFunction(Param1、Param2、window.YourOptionalParameter)

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

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

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