DOMException の stack プロパティ
core-js が DOMException の polyfill を実装していて、stack プロパティってどうなってるんだろうと思って調べてみたまとめ。
色々試してたけどコンストラクタ云々は WPT を見たら一発だった。
https://gyazo.com/33d17b9535579a06a504e75dc2dc3bba
前提
JavaScript において Error の stack プロパティは各エンジンによる独自実装で、ECMAScript として仕様に定まっているわけではない。Stage 1 Error Stacks で仕様にするために作業中。各々で実装が異なっている。 V8 (Chrome, Deno, Node.js)
stack プロパティをオブジェクトが直接所有する。
Error.captureStackTrace という非標準の函数を使うことで任意のオブジェクトに stack プロパティを割り当てることが出来る。Error のコンストラクタで内部的に Error.captureStackTrace と同じ処理が呼ばれており、そのサブクラスのインスタンスを作った場合では明示的にこの函数を呼ぶ必要はない(もちろん親クラスの Error のコンストラクタを呼ぶ必要はある)。
SpiderMonkey (Firefox)
Error.prototype.stack というアクセサプロパティが存在する。
JavaScriptCore (Safari)
おそらく Error のコンストラクタ内の処理でオブジェクトに stack プロパティを付与している。
DOMException
DOMException は Error のサブクラスという事になっている。実装にも依るが多分親クラスである Error のコンストラクタは呼ばれていない。ちなみに code プロパティは name に対応付けられたものになっている(レガシー機能なため、新しい name に対しては特に定まっていない)。
code: (ts)
declare class Error {
constructor(message?: string, options?: { cause?: any }): Error;
(message?: string, options?: { cause?: any }): Error;
name: string;
message: string;
stack?: string;
cause?: any;
}
declare class DOMException extends Error {
constructor(message?: string, name?: string);
readonly name: string;
readonly message: string;
readonly code: number;
}
DOMException の stack プロパティ
仕様によると DOMException は Error に stack プロパティがある場合には同様に割り当てなければならない。
Additionally, if an implementation gives native Error objects special powers or nonstandard properties (such as a stack property), it should also expose those on DOMException instances.
実際にどうなってるのか確認する。通常の例外発生時、どのブラウザ環境についても DOMException は stack プロパティを何らかの形で持っている。以下のようなコードで確認できる。
code: js
try {
const div = document.createElement("div");
document.body.removeChild(div);
} catch (e) {
console.log(e.stack);
}
Deno (v1.14.2) や Node.js (v17.0.0-rc.0) では以下で調べられる。どうやら Deno は stack プロパティを持たないらしい。
code: (js)
try {
structuredClone(Symbol());
} catch (e) {
console.log(e.stack);
}
さて DOMException をコンストラクタから作った場合について確認する。どうやら Firefox 以外 stack プロパティを持たない。面白いことに V8 で実装されている Node.js (v17.0.0-rc.0) では stack プロパティを持つように実装されている。
code: js
try {
throw new DOMException();
} catch (e) {
console.log(e.stack);
}
まとめると以下のようになる。
table:stack プロパティの有無
Error DOMException(通常) DOMException(コンストラクタ)
V8 (Chrome 94) ⭕ ⭕ ❌
V8 (Deno v1.14.2) ⭕ ❌ ❌
V8 (Node.js v17.0.0-rc.0) ⭕ ⭕ ⭕
SpiderMonkey (Firefox 92) ⭕ ⭕ ⭕
JavaScriptCore (Safari 15) ⭕ ⭕ ❌
Deno についてはバグっぽいので報告しようと思ったら、丁度最新のコミットで解決していた。
スタックトレースの文字列を改善する PR を出してマージされた。