JavaScriptのObject.isExtensible():オブジェクトに項目を追加できるか調べる
Object.isExtensible()でオブジェクトの拡張可否を調べる方法を解説。引数・戻り値、ブラウザーとNode.jsの実行手順、期待出力、既存値の更新との違いや例外の注意点を学べます。
目的:項目を追加できない原因を調べる
ライブラリーから受け取ったオブジェクトに項目を追加すると、TypeErrorになることがあります。調査の手掛かりになるのが、拡張可能かどうかを返すObject.isExtensible()です。
ここでいう拡張とは、オブジェクト自身のプロパティを新しく追加することです。値を書き換えられるか、入れ子のデータを変更できるかとは別の状態を表します。
例えば、設定に診断用のdebugを追加できない原因を探す場面で使えます。追加禁止にする処理がどこかにあるかを調べる前に、現在の状態を確認できるためです。本記事では状態の判定と読み取り方に焦点を当てます。MDNの仕様説明
動作環境とバージョン
Object.isExtensible()はJavaScriptの標準組み込み関数です。ブラウザーとNode.jsの両方で利用でき、DOMや外部パッケージに依存しません。
2026年11月9日時点のMDNでは、2015年7月からブラウザー間で広く利用可能な機能とされています。本記事のコードは現在のChrome、Edge、Firefox、Safariと、Node.js 22以降を対象にします。これは記事の対象環境であり、このAPIがNode.js 22で初めて導入されたという意味ではありません。
古い実装ではプリミティブ値の扱いに差があります。ES5ではオブジェクト以外を渡すと例外でしたが、ES2015以降はfalseです。古いブラウザーを対象にする場合、関数の有無だけでなくこの違いにも注意してください。MDNの互換性と非オブジェクト引数の説明
Node.jsはV8を使い、安定したJavaScript機能を通常は追加フラグなしで提供します。本記事の例にも実験用フラグは不要です。Node.jsの言語機能に関する説明
引数と戻り値
呼び出し方は次のとおりです。インスタンスのメソッドではなく、Objectから呼び出します。
Object.isExtensible(obj);obj:状態を調べたい値です。通常はオブジェクトを渡します。- 戻り値が
true:対象は拡張可能です。 - 戻り値が
false:対象は拡張不可能、またはES2015以降ではオブジェクト以外です。
通常のオブジェクトは作成時に拡張可能です。追加禁止、封印、凍結などの処理を受けたオブジェクトではfalseになります。判定のために通常のオブジェクトを変更することはありません。
この関数は同期処理です。戻り値はPromiseではないため、awaitや非同期コールバックは必要ありません。MDNの引数・戻り値
falseだけで入力の種類は区別できない
Object.isExtensible(null)と、追加禁止のオブジェクトを調べた結果は、どちらもfalseです。入力がオブジェクトであることも必要なら、別途型を確認します。例えば通常のデータオブジェクトを受け付ける処理では、value !== null && typeof value === "object"などの条件を先に設けます。
コピーして実行する
次のコードは単独で動作します。通常のオブジェクト、追加禁止のオブジェクト、凍結されたオブジェクトを比較し、既存値の更新と新規追加の違いも確認します。
(() => {
"use strict";
const editable = { theme: "light" };
const fixedShape = Object.preventExtensions({ theme: "light" });
const frozen = Object.freeze({ theme: "light" });
console.log("通常:", Object.isExtensible(editable));
console.log("追加禁止:", Object.isExtensible(fixedShape));
console.log("凍結:", Object.isExtensible(frozen));
console.log("数値:", Object.isExtensible(123));
console.log("null:", Object.isExtensible(null));
fixedShape.theme = "dark";
console.log("既存値の更新:", fixedShape.theme);
try {
fixedShape.debug = true;
} catch (error) {
console.log("追加の失敗:", error.name);
}
console.log("追加後のdebug:", fixedShape.debug);
})();ブラウザーでの実行方法
通常のWebページを開き、開発者ツールのConsoleを表示します。コード全体を入力して実行すると、Consoleに結果が表示されます。外部通信やHTMLファイルの準備は不要です。
外側の関数によって変数の有効範囲を閉じているため、同じコードを繰り返し実行しても、トップレベルのconstの再宣言による衝突を避けられます。
Node.jsでの実行方法
Node.js 22以降を用意し、コードをextensible-demo.cjsとして保存します。ターミナルで保存先のフォルダーへ移動し、次を実行します。
node extensible-demo.cjs.cjsにすることで、周囲のプロジェクトのモジュール設定に左右されずCommonJSとして実行できます。今回はモジュールの読み込み自体が不要です。ファイル名をnodeコマンドに渡す実行方法は、Node.jsの公式手順でも説明されています。
期待出力
通常: true
追加禁止: false
凍結: false
数値: false
null: false
既存値の更新: dark
追加の失敗: TypeError
追加後のdebug: undefined追加禁止でも、もともとある書き込み可能なthemeは更新できます。一方、debugは新規項目なので追加できません。例外を捕捉しているため、その後の出力まで処理が続きます。
この出力は仕様から導いた期待値です。本記事の作成時にはコードを実行していません。
失敗例と判定の限界
falseを「すべて変更不可」と解釈する
実行例のfixedShapeとfrozenは、どちらも判定結果がfalseです。しかし、既存プロパティの書き換え可否は異なります。
そのため、この結果だけを使って「読み取り専用」と表示すると誤解を生みます。診断画面なら「新規項目の追加不可」と表示し、特定項目の更新可否は別の情報として扱うのが適切です。
strictモードを付けずに追加失敗を見落とす
通常の非拡張オブジェクトに代入で新規項目を追加すると、strictモードではTypeErrorになります。非strictモードでは追加が黙って無視されるため、例外が出なかったことを成功の根拠にできません。
実行例では関数内に"use strict"を置き、失敗を例外として観察できるようにしています。エラーメッセージの文面は実行環境で異なるため、期待出力にはerror.nameを使っています。MDNの追加失敗の説明
trueを「どの代入も成功する」と解釈する
拡張可能という結果は、特定のプロパティ名への代入成功を保証しません。既存プロパティの書き込み制限や、継承したアクセサー、Proxyによる制御などは別に関係します。
また、判定後に別の処理で追加禁止にされれば、以前の結果は使えません。特に判定と代入の間にawaitを挟む設計では、結果を長期間保存して使わないようにします。実際の更新処理に必要な例外処理は残してください。
Proxyでは判定そのものが失敗する
ProxyではisExtensibleトラップが呼ばれることがあります。その結果が対象の実際の拡張性と矛盾するとTypeErrorになります。したがって、任意のオブジェクトを受け取る診断ツールでは、判定処理にも例外への備えが必要です。MDNのProxyに関する制約
(() => {
const inconsistent = new Proxy({}, {
isExtensible() {
return false;
}
});
try {
console.log(Object.isExtensible(inconsistent));
} catch (error) {
console.log("判定の失敗:", error.name);
}
})();期待出力は判定の失敗: TypeErrorです。空の対象オブジェクトは拡張可能なのに、トラップがfalseを返すためです。
活用事例と設計上の改善案
ライブラリー連携の調査では、受け取り直後と加工直前で拡張性を記録すると、追加できなくなった段階を絞り込めます。設定オブジェクトの診断画面でも、値そのものと一緒に追加可否を表示すると、状態を説明しやすくなります。
ただし、診断用の情報を付けるために、相手が管理するオブジェクトへ直接プロパティを追加する設計には注意が必要です。拡張性の判定を繰り返すより、元データと補足情報を別に保持する構成を検討してください。
例えば{ data: received, debug: true }という外側のオブジェクトを自分で用意すれば、受信データ自身への追加は不要です。元データの参照は共有されるためコピーにはなりませんが、補足情報を所有する場所が明確になります。
まずObject.isExtensible()で原因を確認し、その後、直接変更が本当に必要かを判断する。この順序なら、判定APIを問題の隠蔽ではなく設計の改善につなげられます。
公式参考資料
Googleの優先するニュース提供元にSEの部屋を追加
Googleで、いつも読みたい情報源を選べます。登録可否はGoogleの画面で確認できます。
候補にSEの部屋が表示されない場合は、まだ追加できません。