JavaScript の
typeof は実際には非常に複雑ですが、多くのことを行うために使用できますが、多くの奇妙な動作もあります。 この記事では、その複数の用途をリストし、既存の問題と解決策も指摘します。
この記事を読む前提は、プリミティブ値とオブジェクト値の違いを理解する必要があるということです。
変数が存在し、値があるかどうかを確認します
typeof は、次の 2 つの場合に「未定義」を返します:
変数が宣言されていない
変数の値が未定義
例:
> typeof undeclaredVariable === "未定義"
> vardeclaredVariable;
>
&g t; タイプが未定義です '未定義' 値が未定義かどうかを検出する方法は他にもあります: > var value = unknown;> value === unknowntrue undeclared 変数がオンの場合、typeof のみがエラーを報告せずに宣言されていない変数を正常に検出できるため、例外がスローされます: > undeclaredVariable === unknownReferenceError: undeclaredVariable が定義されていません注 : 未初期化変数、パラメータが渡されない仮パラメータ、および存在しないプロパティは常にアクセス可能であり、値は常に未定義であるため、上記の問題は発生しません。 true > (function (x) { return x === 未定義 }())true > = == 未定義true注: したがって、宣言されていない可能性のあるグローバル変数の存在を検出したい場合は、if(window.maybeUndeclaredVariable){} を使用することもできます。
問題: このようなタスクを完了する場合、typeof は非常に複雑に見えます
解決策: この種の操作はあまり一般的ではないため、より良い解決策を見つける必要はないと感じる人もいます。 しかし、おそらく誰かが特別な演算子を提案するでしょう:
>
> defined undeclaredVariable
false
または、おそらく誰かが検出を必要とします。変数
& & gt; Declared UndeClaredvariable
false
& & gt; Var Declaredvariable; 演算子は、define() と同等であり、上記で宣言された演算子は、exists() と同等です。
値が未定義または null に等しいかどうかを判断する
問題: 値が定義されているかどうか (値が未定義でも null でもない) を検出したい場合、最も有名な奇妙な症状の 1 つに遭遇したことになります。 of typeof (バグと考えられます): typeof null returns "object":
> typeof null
'object'
翻訳者注: これは元の JavaScript 実装のバグであるとしか言えません。標準はこれが標準化されています。 V8 では一度 typeof null === "null" を修正して実装しましたが、最終的には実行不可能であることが判明しました。 http://wiki.ecmascript.org/doku.php?id=harmony:typeof_null。
(注釈: null を操作すると typeof は "object" を返します。これは JavaScript 言語自体のバグです。残念ながら、既存のコードがすでにこのパフォーマンスに依存しすぎているため、このバグは修正されることはありません。しかし、null はこの問題については stackoverflow で議論があります: http://stackoverflow.com/questions/801032/null-object-in-javascript/7968470@justjavac)
解決済みの解決策: typeof を使用しないでください。このタスクでは、代わりに次の関数を使用します:
function isDefined(x) {
return x !== null && x !== unknown;
}
another 1 つの可能性は、「デフォルト値演算子」を導入することです。 "。myValue が定義されていない場合、次の式は defaultValue を返します:
myValue ??defaultValue
上記の式は次と同等です:
(myValue !== unknown && myValue !== null) ? myValue :defaultValue
または:
myValue ??=defaultValue
は、実際には次のステートメントを簡略化したものです:
myValue = myValue ??defaultValue
bar などのネストされたプロパティにアクセスするとき、次の演算子の助けが必要になるかもしれません:
obj.foo.bar
obj または obj.foo が定義されていない場合、上記の式は例外をスローします。 演算子 .?? を使用すると、上記の式は、属性をレイヤーごとに移動するときに、値が未定義または null である最初に見つかった属性を返すことができます:
obj.??foo.??bar
:
(obj === 未定義 || obj === null) ?
: (obj.foo === unknown || obj.foo === null) ? obj.foo
: obj.foo.bar
オブジェクト値とプリミティブ値を区別する
以下の関数を使用しますx がオブジェクト値かどうかを検出するには:
function isObject(x) {
return (typeof x === "function"
|| (typeof x === "object" && x !== null ));
}
問題: typeof は関数とオブジェクトを異なる型として扱い、typeof null は「object」を返すため、上記の検出はより複雑になります。
解決策: 次の方法もオブジェクトの検出によく使用されます。値:
function isObject2(x) {
return x === Object(x);
}
警告: ここで検出するには、instanceof Object を使用できると思うかもしれませんが、instanceof は次のようにオブジェクトを使用します。プロトタイプはインスタンスの関係を決定するために使用されるため、プロトタイプのないオブジェクトをどうするか: var obj = Object.create(null);
>
obj Indeed はオブジェクトですが、値のインスタンスではありません: > typeof obj'object'> obj instanceof Objectfalseオブジェクトですが、実際に存在し、用途があります。 翻訳者注: Object.prototype は、プロトタイプのない唯一の組み込みオブジェクトです。 & & Gt; object.getprototypeof (object.prototype) null & gt; Typeoflact.protothpe'Object' & gt; オブジェクト lFalse の型は何ですか? typeof は、プリミティブ値の型を確認する最良の方法です。問題: typeof null の奇妙な動作に注意する必要があります。 > typeof null // 注意してください! 'object' 解決策: 次の関数でこの問題を解決できます (この使用例の場合のみ)。 function getPrimitiveTypeName(x) { var typeName = typeof x; switch(typeName) { case "未定義": case "boolean": case "number": case "文字列: > : 実装するgetTypeName() 関数。元の値の型だけでなく、オブジェクトの値の内部 [[Class]] 属性も返すことができます。 この関数の実装方法は次のとおりです (翻訳者注: jQuery の $.type はそのような実装です) 特定の値が関数であるかどうかtypeof を使用して、値が関数であるかどうかを検出できます。 > typeof function () {}'function'> typeof Object.prototype.toString'function' 原則として、instanceof Function もこの要件を検出できます。 一見すると、よりエレガントな書き方に見えます。 ただし、ブラウザには癖があります。すべてのフレームとウィンドウに独自のグローバル変数があります。 したがって、あるフレームから別のフレームにオブジェクトを渡す場合、2 つのフレームのコンストラクターが異なるため、instanceof は正しく機能しません。 ECMAScript5 に Array.isArray() メソッドがあるのはこのためです。 オブジェクトが特定のコンストラクターのインスタンスであるかどうかをチェックするためのクロスフレームワーク メソッドがあれば便利です。 上記の getTypeName() は利用可能な回避策ですが、より根本的な解決策がある可能性があります。 概要 以下に挙げるものは、現時点で JavaScript で最も緊急に必要とされるものであり、typeof の現在の責任の機能の一部を置き換えることができます: isDefined() (Object.isDefined() など) : 関数または演算子として使用できます isObject() getTypeName() オブジェクトが指定されたコンストラクターのインスタンスであるかどうかを検出するクロスフレームワークメカニズム Check変数 このような要件が宣言されていれば、独自の演算子は必要ないかもしれません。