変数===未定義vs typeof変数===「未定義」


300

jQueryのコアスタイルガイドラインは、変数が定義されているかどうかを確認するには、2つの異なる方法を提案します。

  • グローバル変数: typeof variable === "undefined"
  • ローカル変数: variable === undefined
  • プロパティ: object.prop === undefined

jQueryがグローバル変数に1つのアプローチを使用し、ローカル変数とプロパティに別のアプローチを使用するのはなぜですか?


なぜJQueryが両方のアプローチを使用するのかという質問には答えられませんが、JavaScriptには、これら2つのことが微妙に異なることを意味する興味深い癖があります。ほとんどの場合は問題になりません(つまり、コードが正気である場合)が、それでも違いがあります。ここに記述を追加します-wtfjs.com/2010/02/15/undefined-is-mutable
Spudley

2
@Struppiが指摘したように、jQueryの最も外側の関数にはundefinedという名前の引数があります。jQuery内でfoo === undefinedは、グローバル(window.undefined)ではなくundefinedのローカルコピーをチェックしています。これは、非常識なコードによって変更された可能性があります。undefinedが変更可能であるという事実は、注目に値するものであり、あなたがそうしたことをうれしく思います。(+1)
Patrick McElhaney、2011年

1
その記事の現在のリンクはwtfjs.com/wtfs/2010-02-15-undefined-is-mutable
enigment

回答:


366

宣言されていない変数の場合、typeof fooは文字列リテラルを返します"undefined"が、IDチェックfoo === undefinedはエラー「fooが定義されていません」をトリガーします。

ローカル変数(どこかで宣言されいることがわかっている)の場合、そのようなエラーは発生しないため、同一性チェックが行われます。


3
@goreSplatter現在、削除することはできません。:-)選ぶのは大変でしたが、質問の言い方では、この答えの方が適しています。(私がそうであったように)一般的に未定義の動作に興味がある人は、他の回答、特に@Timも確認する必要があります。
Patrick McElhaney、2011年

4
typeof foo; // -> "undefined"文字列であり、プリミティブ値ではないことを強調するために、引用符()を追加しますundefined
c24w 2013

117

私はtypeof foo === "undefined"どこでも使用することに固執します。それは決して失敗することはありません。

jQueryが2つの異なるメソッドを推奨する理由はundefined、jQueryコードが存在する関数内で独自の変数を定義するため、その関数内でundefined外部からの改ざんから安全であると考えています。また、誰かが2つの異なるアプローチをベンチマークし、それfoo === undefinedがより速いことを発見したため、それが進むべき道であると判断したことも想像します。[更新:コメントに記載されているように、との比較undefinedも若干短いため、考慮 に入れることができます。]ただし、実際の状況での利益はまったく重要ではありません。失うことは重要です。比較のためにホストオブジェクトのプロパティを評価すると、エラーがスローされますが、typeof チェックすることはありません。

たとえば、次のコードはIEでXMLの解析に使用されます。

var x = new ActiveXObject("Microsoft.XMLDOM");

loadXML安全にメソッドがあるかどうかを確認するには:

typeof x.loadXML === "undefined"; // Returns false

一方:

x.loadXML === undefined; // Throws an error

更新

typeof私が言及するのを忘れていたチェックのもう1つの利点は、チェックが行わない宣言されていない変数でも機能しfoo === undefined、実際にはがスローされることReferenceErrorです。思い出させてくれた@LinusKleenに感謝します。例えば:

typeof someUndeclaredVariable; // "undefined"
someUndeclaredVariable === undefined; // throws a ReferenceError

結論:常にtypeofチェックを使用します。


10
ティムありがとう。パフォーマンスについてのあなたのポイントは理にかなっています。jQueryチームは、ファイルサイズへの影響をより懸念している可能性があります。foo === undefinedを最小化すると、おそらくのようなものf===uになりますtypeof foo === "undefined"が、にしか削減できませんtypeof f==="undefined"
Patrick McElhaney、2011年

1
あなたはvar u = "undefined"それを定義してに減らすことができますtypeof f==u、それは物事を改善しますが、それでもまだ大きいです。
Tim Down

5
良い点typeofですが、宣言されていない変数に対する安全性が利点かどうかはわかりません。どちらかといえば、タイプミスが簡単に過ぎてしまい、宣言されていない変数のタイプを実際に確認したい場合はわかりません。
David Tang

2
@ Box9:別のライブラリの存在を確認するためにライブラリで使用することは想像できます。
Tim Down、

2
@jontro:それがJSLintを使わない理由の1つです。
Tim Down

29

typeof-variantを使用するもう1つの理由:undefined再定義できます。

undefined = "foo";
var variable = "foo";
if (variable === undefined)
  console.log("eh, what?!");

結果がtypeof variable できません。

更新:これはES5の場合とundefinedは異なり、グローバルは構成や書き込みができないプロパティです。

15.1.1グローバルオブジェクトの値プロパティ
[...]
15.1.1.3 undefined
の値undefinedは未定義です(8.1を参照)。このプロパティには、属性
{[[Writable]]:false、[[Enumerable]]:false、[[Configurable]]:false}があります。

しかし、それでもローカル変数によってシャドウされる可能性があります。

(function() {
  var undefined = "foo";
  var variable = "foo";
  if (variable === undefined)
    console.log("eh, what?!");  
})()

またはパラメータ:

(function(undefined) {
  var variable = "foo";
  if (variable === undefined)
    console.log("eh, what?!");  
})("foo")

17
ES5では再定義できません。
Ry-

6
undefinedES5でグローバルプロパティを再定義することはできませんが、ローカル変数を使用してシャドウすることができます。void 0より短く、より安全です。
Oriol

7

のではundefined常に宣言されていませんが、jQueryのは宣言しundefined、その主な機能に。したがって、undefined内部ではsafe 値を使用しますが、外部では、typeofスタイルを使用して安全にします。



1

ローカル変数の場合、localVar === undefinedローカルスコープ内のどこかで定義されている必要があるか、ローカルとは見なされないため、でのチェックは機能します。

ローカルではなく、どこにも定義されていない変数の場合、チェックsomeVar === undefinedは例外をスローします:Uncaught ReferenceError:j is not defined

ここに私が上に言っていることを明確にするいくつかのコードがあります。さらに明確にするために、インラインコメントに注意してください

function f (x) {
    if (x === undefined) console.log('x is undefined [x === undefined].');
    else console.log('x is not undefined [x === undefined.]');

    if (typeof(x) === 'undefined') console.log('x is undefined [typeof(x) === \'undefined\'].');
    else console.log('x is not undefined [typeof(x) === \'undefined\'].');

    // This will throw exception because what the hell is j? It is nowhere to be found.
    try
    {
        if (j === undefined) console.log('j is undefined [j === undefined].');
        else console.log('j is not undefined [j === undefined].');
    }
    catch(e){console.log('Error!!! Cannot use [j === undefined] because j is nowhere to be found in our source code.');}

    // However this will not throw exception
    if (typeof j === 'undefined') console.log('j is undefined (typeof(x) === \'undefined\'). We can use this check even though j is nowhere to be found in our source code and it will not throw.');
    else console.log('j is not undefined [typeof(x) === \'undefined\'].');
};

上記のコードを次のように呼び出すと、

f();

出力は次のようになります。

x is undefined [x === undefined].
x is undefined [typeof(x) === 'undefined'].
Error!!! Cannot use [j === undefined] because j is nowhere to be found in our source code.
j is undefined (typeof(x) === 'undefined'). We can use this check even though j is nowhere to be found in our source code and it will not throw.

上記のコードを次のように呼び出す場合(実際には任意の値を使用):

f(null); 
f(1);

出力は次のようになります。

x is not undefined [x === undefined].
x is not undefined [typeof(x) === 'undefined'].
Error!!! Cannot use [j === undefined] because j is nowhere to be found in our source code.
j is undefined (typeof(x) === 'undefined'). We can use this check even though j is nowhere to be found in our source code and it will not throw.

次のようなチェックを行うと、typeof x === 'undefined'本質的にこれを求めています。ソースコードのどこかに変数xが存在する(定義されている)かどうかを確認してください。(多かれ少なかれ)。C#またはJavaを知っている場合、このタイプのチェックは行われません。存在しない場合はコンパイルされないためです。

<==フィドルミー==>


1

概要:

グローバルスコープでは、変数が宣言されていないか、値がundefined次の場合にtrueを返します。

var globalVar1;

// This variable is declared, but not defined and thus has the value undefined
console.log(globalVar1 === undefined);

// This variable is not declared and thus will throw a referenceError
console.log(globalVar2 === undefined);

グローバルスコープでは、変数が宣言されているかどうか100%確信できないため、これによりreferenceErrorが発生する可能性があります。typeof不明な変数で演算子を使用すると、変数が宣言されていない場合、この問題は発生しません。

var globalVar1;

console.log(typeof globalVar1 === 'undefined');
console.log(typeof globalVar2 === 'undefined');

これは、変数が宣言されていない場合、または現在必要な値を現在保持している場合に、typeof演算子が文字列を返すためです。undefinedundefined


  • ローカル変数を使用すると、この変数が存在することが事前にわかっているため、この問題は発生しません。変数が存在する場合は、それぞれの関数を単純に調べることができます。
  • オブジェクトプロパティを使用すると、この問題は発生しません。存在しないオブジェクトプロパティを検索しようとすると、値も取得されるためです。 undefined

var obj = {};

console.log(obj.myProp === undefined);


-5

typeof a === 'undefined'a === 'undefined'ノードv6.9.1では約2倍高速です。


3
入力したものとは異なります。私はあなたundefinedが第2部を意味していたと思います'undefined'
怖い人
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.