オブジェクト、配列、数値、文字列の区別

まず、jQueryオブジェクトを操作するためにのみ使用するjQuery.eachメソッド。 残りはfor / whileループまたはそれ自体の「各」対応物です。 論理的に思えますが、 ドキュメントでは、上記の方法はどのコレクションにも使用できると書かれています。

この神話を破壊します。



JQueryロジック



jQuery.eachメソッドのロジックを見てみましょう。 入力では、最初のパラメーターのタイプ、より正確には、オブジェクトであるかどうかがチェックされます。

length = obj.length, isObj = length === undefined || jQuery.isFunction( obj );
      
      





lengthプロパティがない場合、これはObjectです。 そして、長さがそうであれば、これは配列です。

非常に普遍的なアプローチではありません。 見てみましょう。



いくつかのプロパティを持つオブジェクト「Obj」を作成しましょう。その中に、書き込みと長さを指定します。

 var Obj = { name: "test", size: 2, length: 5 };
      
      





それをjQuery.eachに渡しましょう:

 $.each( Obj, function() { console.log( this, arguments ); } );
      
      





実行結果:

 Window [0, undefined] Window [1, undefined] Window [2, undefined] Window [3, undefined] Window [4, undefined]
      
      





失敗。 jQueryはそれを配列として定義し、forループにダミーの長さプロパティを使用しました。

しかし、この問題を回避する方法は? いくつかのアイデアがありました。 これから徐々にそれらを検証し、最も適切で普遍的な実装に到達します。



方法1:Typeof



この方法は私たちには適していない、なぜなら そして、オブジェクトと配列の両方のtypeofは「オブジェクト」です。 さらに、文字列と数値を区別する必要がある場合、new演算子を使用して作成された場合、再び「オブジェクト」を取得します。



方法2:instanceof



ここで私は間違っていました。 帽子だと思って、適切な方法が見つかりました。

しかし、次の落とし穴を避けることはできませんでした。

 var a = {}; a instanceof Object; => true var b = []; b instanceof Array; => true var c = 5; c instanceof Number; => false var d = ""; d instanceof String; => false
      
      





オブジェクトと配列に問題はありません。 ただし、instanceofは、new演算子を使用して作成された場合にのみ、数字と文字列を処理します。 どうぞ



方法3:コンストラクター



これが作業方法です。 コンストラクターの比較。

 var a = {}; a.constructor === Object; => true var b = []; b.constructor === Array; => true var c = 5; c.constructor === Number; => true var d = ""; d.constructor === String; => true
      
      





全体像については、結果を比較する表:

方法 タイプ instanceof コンストラクター
新しい配列() 「オブジェクト」 本当 本当
[] 「オブジェクト」 本当 本当
新しいオブジェクト() 「オブジェクト」 本当 本当
{} 「オブジェクト」 本当 本当
新しい文字列() 「オブジェクト」 本当 本当
「」 「ストリング」 本当
新しい番号() 「オブジェクト」 本当 本当
5 「番号」 本当


結論:



おそらく、各メソッドは次のようになります(デモンストレーションのためにargsの一部を取りませんでした)。

 each: function( obj, callback, args ) { var name, i = 0, length = obj.length, isObj = obj.constructor === Object, isArray = obj.constructor === Array || obj.constructor === String; if ( isObj ) { for ( name in obj ) { if ( callback.call( obj[ name ], name, obj[ name ] ) === false ) { break; } } } else if ( isArray ) { for ( ; i < length; ) { if ( callback.call( obj[ i ], i, obj[ i++ ] ) === false ) { break; } } } }
      
      





ご清聴ありがとうございました。



更新しました。

有益なコメントをありがとう。 この記事の目的は、まず、JavaScriptでデータ型を区別する方法を示すことであり、jQueryのバグを明らかにすることではありません。

「toString」を使用する方法の方が適していることに同意します。 すぐに記事を修正します。 フィードバックをありがとう。 このトピックは私にとって興味深いので、最良の方法も見つけたいと思います。



All Articles