JSデータ型検出のさまざまな方法の概要

JSデータ型検出のさまざまな方法の概要

背景

ご存知のとおり、js は動的型システムとプロトタイプベースの継承を使用する、動的な弱い​​型付けのスクリプト言語です。

型に対する静的制約がないため、データ型に起因するプログラム エラーはコンパイル段階では検出できません。堅牢なコードを書くには、実行時にさまざまなチェックと互換性を実行する必要があります。そのため、データ型を巧みに正確に検出する能力は、この言語を習得するための最も重要な基礎の 1 つとなっています。

データ型を決定する方法は何ですか?

一般的には、typeof、instanceof、Object.prototype.toString、コンストラクタ、ダックタイピング、特定の型の検出メソッドArray.isArray()、Number.isNaN()などが大まかに挙げられます。メソッドは多数ありますが、使用シナリオは異なります。

1. typeof を使用して基本データ型を決定します。

戻り値は、未定義、文字列、数値、ブール値、オブジェクト、関数、シンボルです。

公式に提供されている型検出演算子である typeof は、undefined、文字列、ブール値、シンボルなどの基本的なデータ型と関数を検出する際に非常に信頼性が高いことがわかります。パフォーマンスが低迷した主な理由は

1) 特定のオブジェクト タイプ (配列、日付、正規表現) を区別できません。
2) typeof null === 'object' // は真です。 。 。 。

欠陥 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つの方法で作成されたオブジェクトを指します。

  • 新しいオブジェクト
  • オブジェクトリテラルの作成 {}
  • オブジェクトを作成します(null)

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 をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • JavaScript の基礎におけるデータ型の詳細な説明
  • JSにおける4つのデータ型判定方法
  • データ型の判断における js typeof と instanceof の違いと、その開発と使用について
  • JavaScriptの基本構文とデータ型の詳細な説明
  • この記事では、jsのデータ型とデータ構造の世界を紹介します。
  • JS を使用してデータ型を決定する 4 つの方法
  • JavaScript の 7 つのデータ型の詳細な説明

<<:  MySQL トランザクションの概念と使用法の詳細な説明

>>:  Tencent Cloudでhive3.1.2を構築する方法を教えます

推薦する

Ubuntu 20.04 に Python 3 仮想環境をインストールする詳細なチュートリアル

以下はすべて仮想マシン上で実行されます1. pip3をインストールするsudo apt で pyth...

Vueは州、都市、地区のカスケード選択を実現します

最近、省、市、地区のカスケード選択効果を実装する必要があります。省、市、地区のデータはすべてローカル...

Docker Swarm クラスタ管理の使用と原理の分析

Swarm クラスター管理導入Docker Swarm は Docker 用のクラスター管理ツールで...

PHP 開発環境の構築に関する win10 docker-toolsbox チュートリアル

画像をダウンロード docker プル mysql:5.7 docker pull php:7.2-...

SQLインジェクションの詳しい解説 - セキュリティ編(第2部)

この記事に誤りがあったり、ご提案がありましたら、お気軽にご連絡ください。よろしくお願いいたします。は...

テーブル内の要素のドラッグと並べ替えの問題について簡単に説明します

最近、要素テーブルを使用すると、並べ替えの問題によく遭遇します。単純な並べ替えであれば、要素の公式が...

JavaScript 改ざん防止オブジェクトの使用例

目次JavaScript 改ざん防止オブジェクト1. 拡張不可能なオブジェクト2. 封印された物体3...

MySQLオンラインデッドロック分析練習

序文MySQL を学習する際に、MySQL のロック メカニズムについて簡単に理解したことがあると思...

MySQLでデータベースデータ保存ディレクトリを変更する方法

序文MySQL データベースのデフォルトのデータベース ファイルは /var/lib/mysql に...

JSタイマーを使用して要素を移動する

JS タイマーを使用して、要素に移動する効果のあるメソッドを作成します。実装のアイデアは、まず要素の...

ファイル操作のためのLinuxシステムコール

目次1. ファイルを開くパラメータの紹介2. ファイルの読み取り3. ファイルを書き込む4. 閉じる...

jQueryメソッド属性の詳細な説明

目次1. jQueryの紹介2. jQueryセレクター2.1 5つの基本セレクタ2.2 4種類の関...

テキストの両側に水平線を描くための CSS のサンプルコード

この記事では、テキスト中央の両側に水平線を引く効果を実現する CSS のサンプルコードを紹介し、皆さ...

nginx の http リクエスト処理の各段階の詳細な分析

nginx の HTTP モジュールを作成する場合、リクエスト開始時のアクセス許可の有無、コンテンツ...

Macにmysql5.7.18をインストールする詳細な手順

1. ツール今必要なツールは2つあります: MySQLサーバー (mysql-5.7.18)、MyS...