クイズ: 高度なJSエラーマスター
例外は本当に例外的ですか?
JavaScript のエラー、全部把握してると思う?
- エラーハンドリングの腕前を試そう! 💥
- ログインやサインアップは不要です。 ✨
- 選択式問題です。 🤖 … 普通の try‑catch 問題とは違います!
JSON.stringify(error) は何を返す?
const error = new Error('Oops');console.log(JSON.stringify(error));Error オブジェクトは列挙できないプロパティ(message、name、stack)を持つため、JSON.stringify() は {} を返します。これは API 応答でエラーを送る際の典型的な落とし穴です。JSON.stringify(error, Object.getOwnPropertyNames(error)) を使うか、代わりにプレーンオブジェクトを作成してください。
Errorオブジェクトの列挙可能なプロパティに注目してください。
これらのチェックの結果は?
class CustomError extends Error {}const err = new CustomError('test');
console.log(err instanceof CustomError);console.log(err instanceof Error);console.log(err instanceof Object);すべてのチェックは true を返します。CustomError は Error を継承し、Error は Object を継承しています。instanceof 演算子はプロトタイプチェーン全体を確認するので、CustomError のインスタンスは Error と Object のインスタンスでもあります。
JavaScriptの継承とプロトタイプチェーンを思い出してください。
同一オリジンの iframe 内で作成した Error オブジェクトを、親ウィンドウの変数 iframeError に渡したとします。親ウィンドウの Error を使う次の判定はどうなりますか?
console.log(iframeError instanceof Error);iframe と親ウィンドウは別々の Error コンストラクタとプロトタイプを持つため、この判定は false です。Object.prototype.toString.call(obj) は別の実行領域のエラーを識別する手掛かりになりますが、Symbol.toStringTag で偽装できるため、本物の Error であることの保証にはなりません。
別の実行領域は別のErrorコンストラクタを持ちます。
文字列をthrowしたらどうなる?
try { throw "Oops!";} catch (e) { console.log(e instanceof Error); console.log(typeof e);}JavaScriptでは任意の値をthrowできる。ここでは e instanceof Error は false で、typeof e は "string" になる。これにより、捕捉した例外がすべてErrorオブジェクトであると想定したエラーハンドリングコードが壊れる可能性がある。デバッグしやすくするため、常にErrorインスタンスをthrowしよう。
JavaScriptではError以外の値もthrowできます。
err.name の値は何ですか?
class CustomError extends Error { constructor(message) { super(message); this.name = this.constructor.name; }}const err = new CustomError('test');console.log(err.name);err.name は "CustomError" です。なぜなら this.constructor.name がクラス名を返すからです。this.name = this.constructor.name を設定するのは、カスタムエラークラスがスタックトレースやエラーメッセージで正しい名前を表示するようにする一般的なパターンです。
this.constructor.name の評価結果に注目してください。
name を設定しない場合の出力は?
class MyError extends Error { // No constructor or name setting}const err = new MyError('test');console.log(err.name);this.name を明示的に設定しないと、エラーは Error クラスからデフォルトの name プロパティ("Error")を継承します。だからカスタムエラークラスではコンストラクタ内で必ず this.name = this.constructor.name を設定すべきです。
Errorのデフォルトのnameプロパティには何が入りますか?
wrapper.cause.message は何を返す?
const original = new Error('Original error');const wrapper = new Error('Wrapper', { cause: original });console.log(wrapper.cause.message);Error.cause(ES2022)はエラーをチェーンさせ、元のエラーコンテキストを保持できる。wrapper.cause は元のエラーを指すので、wrapper.cause.message は "Original error" を返す。これは下位レベルのエラーを上位コンテキストでラップする際に便利だ。
Error.causeはエラーを連鎖させるための機能です。
V8 / Node.js で、Error.captureStackTrace は何をしますか?
function createError(msg) { const err = new Error(msg); Error.captureStackTrace(err, createError); return err;}const error = createError('test');Error.captureStackTrace(V8/Node.js)は、指定した関数(createError)をスタックトレースから除外し、エラーファクトリ関数をエンドユーザーに見えなくします。これにより、ファクトリが呼び出された場所を指す、よりクリーンなスタックトレースが得られます。
V8固有のスタックトレース操作機能です。
エラーメッセージは何ですか?
function validate(value) { if (!value) { throw new Error( `Value ${value} is invalid` ); }}try { validate(undefined);} catch (e) { console.log(e.message);}テンプレートリテラルは補間時に undefined を文字列 "undefined" に変換します。エラーメッセージは "Value undefined is invalid" になります。よりクリーンなメッセージにするには、補間前に value ?? 'null' などのチェックを検討してください。
テンプレートリテラルの補間でundefinedはどうなりますか?
クライアントに何が送られる?
// Express.js routeapp.get('/api/data', (req, res) => { const error = new Error('Database failed'); res.json({ error });});res.json() は内部で JSON.stringify() を使用するため、Error オブジェクトは {} になります。クライアントは {"error":{}} を受け取ります。これを修正するには、res.json({ error: error.message }) または res.json({ error: { message: error.message, name: error.name } }) を使用します。
JSON.stringifyによるErrorオブジェクトの扱いを思い出してください。
Promise.reject() は何を受け取れる?
Promise.reject('string').catch(e => console.log(typeof e));Promise.reject({code: 404}).catch(e => console.log(e.code));Promise.reject(42).catch(e => console.log(e));throw と同様に、Promise.reject() は任意の値(文字列、オブジェクト、数値など)を受け取れます。これにより "string"、404、42 が出力されます。Promise チェーンで捕捉した値の型は常に確認しましょう。特にサードパーティのコードが Error 以外で拒否する可能性がある場合は注意が必要です。
Promiseの拒否値はthrowと同様に任意の値です。
error.code と error.errno の信頼性はどれくらいですか?
const fs = require('fs');fs.readFile('missing.txt', (err, data) => { if (err) { console.log(err.code); // 'ENOENT' console.log(err.errno); // -2 }});code や errno のようなプロパティは環境固有(この場合は Node.js)で、標準の Error オブジェクトには含まれません。ブラウザのエラーにはこれらのプロパティはありません。常に存在を確認しましょう:if (err.code === 'ENOENT') のように、存在すると仮定しないでください。
JavaScriptの実行環境とエラーの種類に注目してください。
これらのチェックは何を返す?
const fakeError = { name: 'Error', message: 'Fake error', stack: 'fake stack'};
console.log(fakeError instanceof Error);console.log(Object.prototype.toString.call( fakeError) === '[object Error]');このコードは false, false を出力します。fakeError は Error のプロトタイプを継承しないプレーンオブジェクトで、Object.prototype.toString.call(fakeError) は "[object Object]" を返します。ただし Symbol.toStringTag を設定するとタグを偽装できるため、この方法は一般的な真正性の検証にはなりません。
一方はプロトタイプチェーンをたどり、もう一方は Symbol.toStringTag の影響を受けるオブジェクトタグを返します。
エラーハンドリングの極意
シリアライズの落とし穴からクロスコンテキストの instanceof 失敗まで、こういった高度な概念がジュニア開発者と、すでに傷だらけのベテランを分けます。
もっと挑戦したいですか? 追加の JavaScript、アルゴリズム、その他の脳トレが揃った 全クイズコレクション をチェックしてください。
