背景ご存知のとおり、js は動的型システムとプロトタイプベースの継承を使用する、動的な弱い型付けのスクリプト言語です。 型に対する静的制約がないため、データ型に起因するプログラム エラーはコンパイル段階では検出できません。堅牢なコードを書くには、実行時にさまざまなチェックと互換性を実行する必要があります。そのため、データ型を巧みに正確に検出する能力は、この言語を習得するための最も重要な基礎の 1 つとなっています。 データ型を決定する方法は何ですか?一般的には、typeof、instanceof、Object.prototype.toString、コンストラクタ、ダックタイピング、特定の型の検出メソッドArray.isArray()、Number.isNaN()などが大まかに挙げられます。メソッドは多数ありますが、使用シナリオは異なります。 1. typeof を使用して基本データ型を決定します。戻り値は、未定義、文字列、数値、ブール値、オブジェクト、関数、シンボルです。 公式に提供されている型検出演算子である typeof は、undefined、文字列、ブール値、シンボルなどの基本的なデータ型と関数を検出する際に非常に信頼性が高いことがわかります。パフォーマンスが低迷した主な理由は
欠陥 2) は、オブジェクト参照の型を決定するときに、typeof x === 'object' && x !== null という 1 つの文を追加することで回避できます。しかし、特定の種類のオブジェクトを区別できないことは、確かに大きな問題点です。 2. instanceofを使用してオブジェクトのデータ型を決定するこの演算子は、コンストラクターのプロトタイプがターゲット オブジェクトのプロトタイプ チェーンに出現するかどうかを検出するために使用されます。 これは予測検出方法です。typeof のように文字列としてデータ型を直接返すのではなく、オブジェクト型のコンストラクタを予測し、最終的にブール値を返す必要があります。 検出ルールは実際には名前から確認でき、インスタンスが特定のコンストラクターによって作成されたかどうかを判断します。原理がわかったので、独自の instanceof を実装してみましょう。 関数 myInstanceof(ターゲット,コンストラクタ){ const baseType = ['文字列', '数値', 'ブール値', '未定義', 'シンボル'] baseType.includes(typeof(target)) の場合 { false を返す } //プロトタイプチェーンは実際にはオブジェクトで構成されたリンクリストです。このリンクリストを走査すると、 プロトタイプを Object.getPrototypeOf(target); とします。 while(プロトタイプ){ //チェーン上に一致するオブジェクトがある場合はtrueを返します if (プロトタイプ === コンストラクター.プロトタイプ) { 真を返す }それ以外{ プロトタイプ = Object.getPrototypeOf(プロトタイプ) } } 偽を返す } コンソールログ(myInstanceof([],配列)) js では、インスタンスはコンストラクターを通じて作成されますが、コンストラクター自体は感情のない生産マシンにすぎないため、すべてがオブジェクトから発生すると広く考えることができます。インスタンスの魂と特性 (パブリック プロパティとメソッド) はすべて、コンストラクターの prototype プロパティによって指されるプロトタイプ オブジェクトから共有され、プロトタイプ オブジェクトはすべて純粋なオブジェクトであり、Object コンストラクターによって作成されます。これにより、次の結果が発生します。 配列の場合、プロトタイプ チェーン上のオブジェクトを走査すると、Array.prototype Object.prototype が表示されます。 また、リテラル値で作成された基本データ型を判定することはできません。例えば 上記の欠陥を補うにはどうすればよいでしょうか。その答えは、上記の特殊なシナリオでは、instanceof の代わりに次のコンストラクターを使用することです。 3. コンストラクター属性を使用するまず、はっきりさせておきましょう。コンストラクターはプロトタイプのプロパティであり、インスタンスはプロトタイプから継承されるため、このプロパティはインスタンス上で直接アクセスすることもできます。 予想以上に良いパフォーマンスで、null と undefined を除けば、基本 (ラッパー) 型やコンストラクタ属性を持つオブジェクト型を正確に判定できます。 instanceof のようにプロトタイプ チェーン全体を走査するのではなく、インスタンスのみで判断するため、Array|Object を正確に区別できます。しかし、致命的な欠陥もあります。インスタンス上のこの属性は変更が簡単すぎるのです。変更されると、このメソッドは意味をなさなくなります。 4. toString メソッドまず、js のオブジェクト型、つまりパッケージング オブジェクトの基本型には toString メソッドがあります。 Object.prototype.toString() から継承され、呼び出しは対応するタイプの文字列タグ "[object Type]" を返します。 この方法は、主人を殴って殺すようなもので、意図せず柳を植えて柳の森を作ったような感じです。本来の機能は、オブジェクトを表す文字列を取得することだけです。現在、js の型検出に使用されており、パフォーマンスは非常に優れています。基本型とオブジェクト型の両方で非常に優れたパフォーマンスを発揮します。欠点を指摘するとすれば、返される文字列が少し複雑で、あまり使い勝手がよくないことだけです。では、単純化してみましょう。 まずは簡略版を書く 関数isType(型,値){ Object.prototype.toString.call(value) === `[object ${type}]` を返します } console.log(isType('配列',[])) console.log(isType('数値',1)) これはあまり使い勝手がよくありません。 'Array' や 'Number' などの型パラメータはスペルミスしやすいです。そのため、メソッドでパラメータを事前に設定し、isArray などの関数を呼び出して返す関数ファクトリを構築できることが期待されます。 IDE では、関数名には文字列よりも優れたコードヒントがあり、スペルミスが発生する可能性が低くなります。 関数isType(type){ 関数(値)を返す{ Object.prototype.toString.call(value) === `[object ${type}]` を返します } } const isArray = isType('配列') 定数isNumber = isType('Number') コンソールログ(isArray([]),isNumber(1)) ここでは高階関数の考え方が使われており、パラメータを保持しながら新しい関数を返します。js では、bind はこれをバインドするだけでなく、パラメータを保持しながら新しい関数を返すこともできると考えられますが、これもここで適しています。 関数isType(型,値){ Object.prototype.toString.call(value) === `[object ${type}]` を返します } const isArray = isType.bind(null,'Array') 定数 isNumber = isType.bind(null,'Number') コンソールログ(isArray([]),isNumber(1)) さらに一歩進んで、パラメータカリー化の考え方を使って変換することができます。 関数isType(型,値){ Object.prototype.toString.call(value) === `[object ${type}]` を返します } 関数curring(fn,...args1){ len = fn.length;とします。 関数を返す(...args2){ 定数args = args1.concat(args2); (引数の長さ<len)の場合{ 戻り値:curring(fn,...args) }それ以外{ fn(...args) を返します } } } const isArray = curring(isType,'Array') const isNumber = curring(isType,'Number') コンソールログ(isArray([]),isNumber(1)) 最後に、サポートされるタイプを充実させれば完了です。 定数型 = [ 「ヌル」、 '未定義'、 '弦'、 '番号'、 「ブール」、 '物体'、 '配列'、 '日付'、 '関数'、 '正規表現', 'シンボル'、 '数学'、 ] 定数チェックタイプユーティリティ = {} types.forEach((type)=>{ checkTypeUtil[`is${type}`] = curring(isType,type) }) 輸出 { チェックタイプユーティリティ } コンソールログ(checkTypeUtil.isArray([])) 5. Array.isArrayを使用して配列を決定する前述のように、instanceof は配列を検出するために使用できます。ただし、iframe によって作成されたマルチウィンドウ環境では、ウィンドウのグローバル環境を分離する必要があるため、各ウィンドウで Array と Array.prototype が異なる必要があります。したがって、iframeA.Array.prototype ≠ iframeB.Array.prototype であるため、iframeA.arr instanceof iframeB.Array は false を返す必要があります。これは確率の低いイベントですが、iframe を使用するシナリオでは、値を相互に渡すことも非常に起こり得ます。 ES6 で提供されている Array.isArray を使用するとこの問題は発生せず、配列を正確に判断できます。 このように投票することができます Array.isArrayの場合 Array.isArray = 関数(x) { Object.prototype.toString.call(x) === '[オブジェクト配列]'を返します。 }; } 6. ArrayLikeとArrayを区別する配列クラスの定義は次のとおりです。
関数isLikeArray(x){ if(!(typeof x === 'object' && x !== null)){ 偽を返す } 戻り値の型は x.length === 'number' && x.length >= 0 && !Array.isArray(x) です } 配列のようなオブジェクトは、Array.from Array.prototype.slice.call(val) を使用して実際の配列に変換できます。 7. オブジェクトが純粋オブジェクト(または通常のオブジェクト)であるかどうかを判断する純粋オブジェクトの定義: 具体的には、次の3つの方法で作成されたオブジェクトを指します。
jqueryとlodashのソースコードは、次の方法で検出されます。 const funcToString = Function.prototype.toString const objectCtorString = funcToString.call(Object) 関数isPlainObject(値){ // toString を使用して最初に他のデータ型を除外します if(!value || !Object.prototype.toString.call(value) === "[object Object]"){ 偽を返す } const proto = Object.getPrototypeOf(値) if(proto === null){//Object.create(null) と互換性があり、true を返します。 } const Ctor = Object.prototype.hasOwnProperty.call(proto,'constructor') && proto.constructor; if(typeof Ctor !== 'function'){ 偽を返す } // ここでは、上記の複数のウィンドウ環境で異なるオブジェクトが発生する問題を回避するために、instanceof を直接使用するのではなく、文字列を使用してコンストラクターがオブジェクトであるかどうかを判断します。if(funcToString.call(Ctor) === objectCtorString){ 真を返す } 偽を返す } コンソールログ(isPlainObject(Object.create(null))) console.log(isPlainObject(新しいオブジェクト)) コンソールログ(isPlainObject({a:1})) 8. NaN を検出するにはどうすればいいですか? Number.isNaN と isNaN の違いは何ですか?結論: Number.isNaN は、渡された値が NaN と直接等しいかどうかを厳密に判断します。 isNaN はまず Number() 変換を実行し、次にそれが NaN かどうかを判断します。 9. ダックタイピング実際、上記のコンストラクタを使用してデータ型を決定するのは、このメソッドの使用です。ある動物がアヒルであるかどうかを判断するには、アヒルのように見えるかどうか、アヒルのように鳴くかどうかといった単純な経験的判断に基づいて大まかな判断を下すことができます。 例えば、オブジェクトがPromiseかどうかを判断するには、次のようにします。 関数isPromise(x){ if (!(x インスタンスの Promise)) { 偽を返す } 戻り値の型は x.then === 'function' です } 要約するJS データ型検出に関するこの記事はこれで終わりです。より関連性の高い JS データ型検出コンテンツについては、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き閲覧してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。 以下もご興味があるかもしれません:
|
<<: MySQL トランザクションの概念と使用法の詳細な説明
>>: Tencent Cloudでhive3.1.2を構築する方法を教えます
目次導入:感情のインストール:一般的な CSS コンポーネントを追加します。既存のコンポーネントにス...
以前の就職面接で面接官が尋ねた質問を覚えています。「インライン要素とは何ですか。ブロックレベル要素と...
1. es起動コマンド: docker run -itd -e TAKE_FILE_OWNERSHI...
序文SpringBoot + Vueのフロントエンドとバックエンドを分離したプロジェクトをどのように...
第二に、キーワードのランキングは、Webページの表示速度にも関係しています(参照:キーワードランキン...
この記事では、アコーディオンを実装するためのjQueryの具体的なコードを参考までに紹介します。具体...
これら 2 つの属性はよく使用されますが、その違いはまとめられていません。それでは、その使い方をまと...
序文みなさんこんにちは。CSS ウィザードの alphardex です。この記事では、three.j...
目次1:mysql実行プロセス1.1: コネクタ1.2: キャッシュ1.3: アナライザー1.4: ...
シンプルなアプリケーションの展開1. ディレクトリ構造: └── Pythonpro #ディレクトリ...
以下にまとめたナレッジポイントはどれもよく使われる貴重な情報ばかりですので、ぜひ上手に集めてください...
目次序文プロミスチェーンMDN エラー連鎖デフォルト処理略語非同期待機序文この記事を書いた理由は、ユ...
スレッドが同時に実行される場合、スレッドがリソースを競合してデータの曖昧さが生じるのを防ぐために、重...
1. まず、お使いのマシンに応じて、MySQL 公式サイトから対応するデータベースをダウンロードしま...