1. ホーム
  2. javascript

[解決済み] 変数が配列であるかどうかを検出する方法

2022-11-04 03:59:29

質問

JavaScript の変数が配列であるかどうかを判断するための、事実上の標準的なクロスブラウザの方法は何でしょうか?

ウェブを検索すると、多くの異なる提案がありますが、いくつかは良く、かなりの数は無効です。

たとえば、次のようなものが基本的なアプローチです。

function isArray(obj) {
    return (obj && obj.length);
}

ただし、配列が空であったり、objが実際には配列ではなくlengthプロパティを実装している場合などはどうなるかに注意しましょう。

では、実際に動作し、クロスブラウザであり、なおかつ効率的に実行できるという点で、どの実装が最も優れているのでしょうか?

どのように解決するのか?

JSにおけるオブジェクトの型チェックは instanceof によって行われます。

obj instanceof Array

オブジェクトがフレームの境界を越えて渡される場合、これはうまくいきません。なぜなら、各フレームはそれぞれ Array オブジェクトを持つためです。これを回避するには、内部の [[クラス]]をチェックすることです。 プロパティを確認することで回避できます。これを取得するには Object.prototype.toString() (を使用します(これはECMA-262で動作が保証されています)。

Object.prototype.toString.call(obj) === '[object Array]'

どちらのメソッドも実際の配列に対してのみ動作します。 arguments オブジェクトやノードリストのような配列に似たオブジェクトではありません。すべての配列のようなオブジェクトは数値の length プロパティを持たなければならないので、このようにチェックします。

typeof obj !== 'undefined' && obj !== null && typeof obj.length === 'number'

なお、文字列はこのチェックを通過してしまいますが、IEではインデックスによる文字列のアクセスができないため、問題が発生する可能性があります。そのため typeof obj !== 'undefined'typeof obj === 'object' とは異なる型を持つプリミティブやホストオブジェクトを除外するために 'object' とは異なる型を持つプリミティブやホストオブジェクトを完全に除外します。これは、手動で除外しなければならない文字列オブジェクトをまだ通過させます。

ほとんどの場合、実際に知りたいことは、数値インデックスを使ってオブジェクトを反復処理できるかどうかです。したがって、オブジェクトが 0 という名前のプロパティがあるかどうかを確認するのが良いかもしれません。

typeof obj[0] !== 'undefined' // false negative for `obj[0] = undefined`
obj.hasOwnProperty('0') // exclude array-likes with inherited entries
'0' in Object(obj) // include array-likes with inherited entries

オブジェクトへのキャストは、配列のようなプリミティブ(例えば文字列)に対して正しく動作するために必要です。

JSの配列に対する堅牢なチェックのためのコードは以下の通りです。

function isArray(obj) {
    return Object.prototype.toString.call(obj) === '[object Array]';
}

と反復可能な(つまり空でない)配列のようなオブジェクトです。

function isNonEmptyArrayLike(obj) {
    try { // don't bother with `typeof` - just access `length` and `catch`
        return obj.length > 0 && '0' in Object(obj);
    }
    catch(e) {
        return false;
    }
}