DataViewの型判定:その「沼」から抜け出すための現場の知恵
フロントエンドの最前線でバイナリデータを扱う機会、増えたよね。WebSocketでのリアルタイム通信、Canvasのピクセル操作、あるいはWebAssemblyとのデータ連携。`ArrayBuffer`を扱う際、避けて通れないのが`DataView`だ。
でも、ふと「今手元にあるこのオブジェクト、本当に`DataView`なのか?」と不安になることはないだろうか。`typeof`を使っても`”object”`しか返ってこないし、`instanceof`も別ウィンドウやiframeを跨ぐと平気で裏切ってくる。
今日は、そんな「JavaScriptの型判定の闇」を突破するための、現場で本当に使える実践的なテクニックを伝授しよう。
—
1. なぜ `typeof` や `instanceof` ではダメなのか
まず、基本の確認だ。
const buffer = new ArrayBuffer(16);
const view = new DataView(buffer);
console.log(typeof view); // -> “object”
見ての通り、`typeof`は「ただのオブジェクト」としか教えてくれない。これでは`Array`なのか、`Date`なのか、はたまた`DataView`なのか、区別がつかない。
次に、よくあるのが `instanceof` だ。
console.log(view instanceof DataView); // -> true
一見これで良さそうだが、実は大きな落とし穴がある。もし君がElectronやiframe、あるいは異なるWindowコンテキストを跨いだコードを書いている場合、「別の環境で作られた`DataView`」に対して`instanceof`は`false`を返すことがあるんだ。これはプロトタイプチェーンが環境ごとに別々に管理されているからだね。
「動くからいいや」で済ませていると、ある日突然、境界条件のバグに泣かされることになる。
—
2. 真の判定法:`Object.prototype.toString.call` という「奥の手」
現場のシニアたちが結局たどり着くのは、`Symbol.toStringTag` を利用したチェックだ。これは、JavaScriptエンジンが内部で「このオブジェクトは何者か」を保持している名前空間を直接覗きに行く方法だ。
/
- 堅牢にDataViewを判定するユーティリティ関数
- @param {unknown} value 判定対象
- @returns {boolean} DataViewであればtrue
/
function isDataView(value) {
// nullやundefined、あるいはオブジェクト型でない場合は即座に弾く
if (!value || typeof value !== ‘object’) {
return false;
}
// Object.prototype.toString を借りて、内部タグを確認する
// DataViewの場合、”[object DataView]” という文字列が返ってくる
return Object.prototype.toString.call(value) === ‘[object DataView]’;
}
// テスト
const buffer = new ArrayBuffer(8);
const view = new DataView(buffer);
console.log(isDataView(view)); // -> true
console.log(isDataView({})); // -> false
これがなぜ最強か。それは、実行環境のプロトタイプチェーンに依存せず、ブラウザが内部的に管理している「タグ(Tag)」を参照するからだ。どんなに環境が入り組んでいても、こいつは裏切らない。
—
3. さらに一歩踏み込む:`buffer` プロパティのチェック
もし、もう少し「泥臭く」ガードを固めたいなら、`DataView`特有のプロパティである`buffer`の存在を確認するのも一つの手だ。ただし、これだけだと「`DataView`っぽい何か」をすり抜けてしまう可能性があるため、必ず先ほどの`toString.call`と組み合わせるのがベストプラクティスだ。
function isStrictDataView(value) {
// 1. 型タグチェック
if (Object.prototype.toString.call(value) !== ‘[object DataView]’) {
return false;
}
// 2. 念のためのプロパティチェック(DataViewであることの補強)
return ‘buffer’ in value && value.buffer instanceof ArrayBuffer;
}
—
プロからのアドバイス:なぜ「型」にこだわるのか
「JavaScriptは動的型付け言語だし、`duck typing`(アヒルのように歩き、アヒルのように鳴くなら、それはアヒルだ)でいいんじゃないの?」という意見もわかる。
しかし、バイナリデータは「型がズレた瞬間」に大事故になる。`DataView`だと思って`getUint32`を叩いた対象が、実はただのプレーンなオブジェクトだったら……ブラウザは即座に例外を投げ、ユーザーの体験はそこで止まる。
型判定を厳密に行うことは、単なる趣味じゃない。「ここで何が来るか100%保証する」という、エンジニアとしての防御的プログラミングの精神なんだ。
今回の `Object.prototype.toString.call` を使った判定方法は、`DataView`だけでなく、`Map`や`Set`、`WeakMap`などの判定にも応用が効く汎用的なテクニックだ。ぜひ、君のプロジェクトの`utils.js`にそっと忍ばせておいてくれ。
現場からは以上だ。また何かあればいつでも聞いてくれよな。

コメント