LoginSignup
2
0

More than 3 years have passed since last update.

isTypedArrayの実装をいくつか

Posted at

JavaScriptでTypedArrayかどうかを判定する方法をまとめました。
意外とどうしたらいいのかわからなくて困りましたからね。

1. 正規表現

正規表現を使う方法です。
babelのランタイム関数 _unsupportedIterableToArray でも似たような正規表現が使われていたりします。1
この方法は今後この正規表現でカバーできないTypedArrayが追加された場合、更新する必要があります。
流石にもうない気がしますが。

また、Object.prototype.toStringと正規表現に依存しているので、@@toStringTagに正規表現にマッチする文字列が入っていたら誤判定します。

const toString = Object.prototype.toString;
const regexp = /^(Big)?(Uin|In|Floa)t(8|16|32|64)(Clamped)?Array$/;
const isTypedArray = (value) => (
    regexp.test(toString.call(value))
);

// 誤判定するケース
isTypedArray({
    [Symbol.toStringTag]: "BigFloat8ClampedArray"
}); // > true

2. %TypedArray%

全てのTypedArrayは%TypedArray%を継承しているので、%TypedArray%のインスタンスかを調べる方法です。
有効でない%TypedArray%のインスタンスもtrueなんですが、%TypedArray%はそもそもエラーで呼べないのでObject.create(%TypedArray%.prototype)でないと作れません。このくらい許しましょう。

const $TypedArray$ = Object.getPrototypeOf(Int8Array);
const isTypedArray = (value) => (
    value instanceof $TypedArray$
);

// 誤判定するケース
isTypedArray(Object.create($TypedArray$.prototype));

3. ArrayBuffer.isView

ArrayBuffer.isViewを使っています。
ネイティブで[[ViewedArrayBuffer]]を持っているか確認しているので、一番堅牢な方法だと思います。
TypedArrayとDataView以外にArrayBuffer.isViewがtrueを返すオブジェクトが追加されたら更新しないといけませんが、まあないでしょう。
仕様書:https://tc39.es/ecma262/#sec-arraybuffer.isview

const isTypedArray = (value) => (
    ArrayBuffer.isView(value) && !(value instanceof DataView)
);
// 誤判定するケースは思いつきませんでした。多分ないと思います。

4. constructor

TypedArrayの配列を作ってconstructorと比較する方法です。
これだとconstructorが上書きされていたりTypedArrayを継承したクラスを判定できません。2
それぞれにinstanceofするように変えてもそれ2番目のでよくね?となります。
また、BigInt64Arrayなどの最近の仕様にしか存在しないものは、対応していないブラウザなどでエラーが出ます。
他のを使いましょう。

const typedArrays = [
    Int8Array,
    Uint8Array,
    Uint8ClampedArray,
    Int16Array,
    Uint16Array,
    Int32Array,
    Uint32Array,
    Float32Array,
    Float64Array,
    BigInt64Array,
    BigUint64Array,
];
const isTypedArray = (value) => (
    typedArrays.includes(value.constructor)
);

// 誤判定するケース
isTypedArray({
    constructor: Int8Array
}); // > true

class MyTypedArray extends Int8Array {}
isTypedArray(new MyTypedArray); // > false

// 代替案
const isTypedArray = (value) => (
    typedArrays.some(ctor => value instanceof ctor)
);

typescript

最後におまけとしてTSの型を置いておきます。

type TypedArray = (
    | Int8Array
    | Uint8Array
    | Uint8ClampedArray
    | Int16Array
    | Uint16Array
    | Int32Array
    | Uint32Array
    | Float32Array
    | Float64Array
    | BigInt64Array
    | BigUint64Array
);

const isTypedArray = (value: unknown): value is TypedArray => (
    // 実装
);

参考

https://tc39.es/ecma262/
https://stackoverflow.com/questions/58280379/how-to-find-the-type-of-a-typedarray


  1. https://babeljs.io/repl[...""]とか書くと確認できると思います。 

  2. TypedArrayを継承して使うことなんてあるんでしょうかね? 

2
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0