Object
Baseline
広く利用可能
*
この機能は広く実装されており、多くのバージョンの端末やブラウザーで動作します。2015年7月以降、すべてのブラウザーで利用可能です。
* この機能の一部は、対応レベルが異なる場合があります。
Object 型は JavaScript のデータ型の一つを表します。これは様々なキー付きコレクションとより複雑な実体を格納するために使用されます。 Object は Object() コンストラクターまたはオブジェクト初期化子/リテラル構文を使用して生成することができます。
解説
JavaScript のほぼすべてのオブジェクトが Object のインスタンスです。一般的なオブジェクトは、プロパティを(メソッドを含めて) Object.prototype から継承していますが、これらのプロパティはシャドウ化(別名オーバーライド)されている場合があります。 Object.prototype を継承しないオブジェクトは、 null プロトタイプを持つオブジェクトか、その他の null プロトタイプオブジェクトの子孫だけです。
Object.prototype オブジェクトへの変更は、その変更の対象となるプロパティやメソッドがプロトタイプチェーンに沿ってさらにオーバーライドされない限り、プロトタイプチェーンを通してすべてのオブジェクトに反映されます。これはとても強力ですが、オブジェクトの動作をオーバーライドしたり拡張したりするのは潜在的に危険をはらむ仕組みでもあります。より安全にするために、 Object.prototype は JavaScript のコア言語で唯一、不変のプロトタイプを持つオブジェクトです。 Object.prototype のプロトタイプは常に null であり、変更できません。
Object の prototype プロパティ
インスタンスから Object.prototype のメソッドを直接呼び出すことは避けるべきです。特に、多態性が意図されていないメソッド(つまり、初期の動作だけが意味を持ち、子孫オブジェクトが意味のある方法でそれを上書きすることはできないメソッド)は避けるべきです。 Object.prototype から子孫するすべてのオブジェクトは、同じ名前を持つが、期待するものとはまったく異なる意味づけを持つ、カスタムの自分自身でプロパティを定義することができます。さらに、これらのプロパティは null プロトタイプオブジェクトには継承されません。オブジェクトを作業するための現行の JavaScript ユーティリティはすべて静的です。もっと具体的には、次の通りです。
valueOf()、toString()、toLocaleString()は多態的な実装として存在し、オブジェクトが賢明な振る舞いを持つ自分自身の実装を定義していることを期待する必要があるので、インスタンスメソッドとして呼び出すことができます。しかし、valueOf()とtoString()は通常、型変換によって暗黙のうちに呼び出されるので、コードの中で自分で呼び出す必要はありません。__defineGetter__()、__defineSetter__()、__lookupGetter__()、__lookupSetter__()は非推奨であり、使用すべきではありません。代わりに静的な代替であるObject.defineProperty()やObject.getOwnPropertyDescriptor()を使用してください。__proto__プロパティは非推奨であり、使用すべきではありません。代替であるObject.getPrototypeOf()およびObject.setPrototypeOf()は静的メソッドです。propertyIsEnumerable()およびhasOwnProperty()メソッドは、それぞれObject.getOwnPropertyDescriptor()およびObject.hasOwn()静的メソッドに置き換えることができます。isPrototypeOf()メソッドは通常、コンストラクターのprototypeプロパティを検査しているのであれば、instanceofで置き換えられます。
意味的に等価な静的メソッドが存在しない場合、または Object.prototype メソッドを本当に使用したい場合は、オブジェクトが予期しない結果をもたらすオーバーライドプロパティを保有しないように、代わりに対象とするオブジェクトの Object.prototype メソッドを直接 call() を呼び出す必要があります。
const obj = {
foo: 1,
// 自分自身でこのようなメソッドを定義すべきではありませんが、
// 外部入力からオブジェクトを受け取っている場合には、このような
// ことが起こらないようにすることはできないかもしれません。
propertyIsEnumerable() {
return false;
},
};
obj.propertyIsEnumerable("foo"); // false; 予期しない結果
Object.prototype.propertyIsEnumerable.call(obj, "foo"); // true; 期待通りの結果
オブジェクトからのプロパティの削除
オブジェクト自体には、自身のプロパティを削除するメソッド (Map.prototype.delete() のようなもの) はありません。これを行うには、 delete 演算子を使用する必要があります。
null プロトタイプオブジェクト
JavaScript では、ほぼすべてのオブジェクトが最終的に Object.prototype から継承しています(継承とプロトタイプチェーンを参照)。ただし、 null プロトタイプオブジェクトは Object.create(null) やオブジェクト初期化子構文 で __proto__: null とすることで作成することができます(注: オブジェクトリテラル内の __proto__ キーは非推奨の Object.prototype.__proto__ プロパティとは異なります)。既存のオブジェクトのプロトタイプを null に変更するには、 Object.setPrototypeOf(obj, null) を呼び出してください。
const obj = Object.create(null);
const obj2 = { __proto__: null };
プロトタイプが null のオブジェクトは、Object.prototype からオブジェクトメソッドを継承していないため、予期しない動作をすることがあります。これは特にデバッグ時に当てはまります。一般的なオブジェクトプロパティの変換/検出ユーティリティ関数はエラーを生成したり、情報を失う可能性があるからです(特に、エラーを無視する暗黙のエラートラップを使用していた場合)。
例えば、 Object.prototype.toString() がないため、デバッグが難しくなることがよくあります。
const normalObj = {}; // 通常のオブジェクトを作成
const nullProtoObj = Object.create(null); // プロトタイプが "null" であるオブジェクトを作成
console.log(`normalObj is: ${normalObj}`); // "normalObj is: [object Object]" と表示
console.log(`nullProtoObj is: ${nullProtoObj}`); // エラー: Cannot convert object to primitive value が発生
alert(normalObj); // [object Object] と表示
alert(nullProtoObj); // エラー: Cannot convert object to primitive value が発生
他のメソッドも失敗します。
normalObj.valueOf(); // {} と表示
nullProtoObj.valueOf(); // エラー: nullProtoObj.valueOf is not a function が発生
normalObj.hasOwnProperty("p"); // "true" と表示
nullProtoObj.hasOwnProperty("p"); // エラー: nullProtoObj.hasOwnProperty is not a function が発生
normalObj.constructor; // "Object() { [native code] }" と表示
nullProtoObj.constructor; // "undefined" と表示
toString メソッドを null プロトタイプオブジェクトに割り当てることで追加することができます。
nullProtoObj.toString = Object.prototype.toString; // 新しいオブジェクトに toString が欠けているため、元の汎用的なものを追加しなおす
console.log(nullProtoObj.toString()); // "[object Object]" と表示
console.log(`nullProtoObj is: ${nullProtoObj}`); // "nullProtoObj is: [object Object]" と表示
通常のオブジェクトが toString() をオブジェクトのプロトタイプに持つのとは異なり、ここでの toString() メソッドは nullProtoObj の自分自身のプロパティです。これは nullProtoObj には (null) プロトタイプがないからです。
また、 Object.setPrototypeOf(nullProtoObj, Object.prototype) を用いて、 null プロトタイプオブジェクトを普通のオブジェクトに戻すこともできます。
実際には、 null プロトタイプを持つオブジェクトは通常、マップの安価な代用として使用されます。 Object.prototype プロパティが存在すると、いくつかのバグが発生します。
const ages = { alice: 18, bob: 27 };
function hasPerson(name) {
return name in ages;
}
function getAge(name) {
return ages[name];
}
hasPerson("hasOwnProperty"); // true
getAge("toString"); // [Function: toString]
null プロトタイプオブジェクトを使用することで、 hasPerson 関数や getAge 関数にあまり複雑さをもたらすことなく、この危険性を除去することができます。
const ages = Object.create(null, {
alice: { value: 18, enumerable: true },
bob: { value: 27, enumerable: true },
});
hasPerson("hasOwnProperty"); // false
getAge("toString"); // undefined
このような場合、データとして格納される他のキーと値のペアと混同される可能性があるため、メソッドの追加は慎重に行う必要があります。
オブジェクトを Object.prototype から継承しないようにすることで、プロトタイプ汚染攻撃を防ぐこともできます。悪意のあるスクリプトが Object.prototype にプロパティを追加した場合、プロトタイプが null であるオブジェクト以外のプログラム内のすべてのオブジェクトにアクセスすることができます。
const user = {};
// 悪意のあるスクリプト
Object.prototype.authenticated = true;
// 認証されていないユーザーを通過させる予期せぬ行為
if (user.authenticated) {
// 機密データにアクセス
}
JavaScript には null プロトタイプオブジェクトを生成する組み込み API もあり、特にオブジェクトをアドホックなキー値の集合として使用しています。例えば、次のようなものです。
Object.groupBy()の返値RegExp.prototype.exec()の返値のgroupsおよびindices.groupsプロパティArray.prototype[Symbol.unscopables](すべての[Symbol.unscopables]オブジェクトはプロトタイプがnullである)import.meta- モジュールの名前空間オブジェクト。
import * as ns from "module";またはimport()から取得したもの。
「null プロトタイプオブジェクト」という用語には、よくプロトタイプチェーンに Object.prototype がないオブジェクトも含みます。このようなオブジェクトは、クラスを使用するときに extends null で作成することができます。
オブジェクト変換
オブジェクトを期待する組み込み処理の多くは、最初に引数をオブジェクトに変換します。この処理をまとめると以下のようになります。
- オブジェクトはそのまま返されます。
undefinedおよびnullの場合はTypeErrorが発生します。数値、文字列、論理値、シンボル、長整数のプリミティブは、それぞれ対応するオブジェクトラッパーに変換されます。
JavaScript でほぼ同じ効果を得るには 2 つの方法があります。
Object.prototype.valueOf():Object.prototype.valueOf.call(x)は、上記で説明したオブジェクト変換の段階と全く同じように、xを変換します。Object()関数:Object(x)はxを変換するために同じアルゴリズムを使用しますが、undefinedとnullはTypeErrorを発生しません。
オブジェクト変換を使用する場所には以下のようなものがあります。
for...inループのobject引数。Arrayメソッドのthis値。Objectのメソッド、例えばObject.keys()の引数。- プリミティブ値はプロパティを持たないため、プリミティブ値に対してプロパティがアクセスされると自動的にボックス化されます。
- 厳格モードでない関数を呼び出したときの
this値。プリミティブはボックス化され、nullとundefinedはグローバルオブジェクトに置き換わります。
プリミティブ変換とは異なり、オブジェクト変換処理は toString メソッドや valueOf メソッドのようなカスタムコードを呼び出さないので、それ自体は何か方法で監視することはできません。
コンストラクター
Object()-
新しい
Objectオブジェクトを生成します。これは指定された値のラッパーです。
静的メソッド
Object.assign()-
1 個以上のソースオブジェクトから、自身の列挙可能なプロパティの値をすべてターゲットオブジェクトにコピーします。
Object.create()-
指定されたプロトタイプオブジェクトとプロパティから、新しいオブジェクトを生成します。
Object.defineProperties()-
指定された記述子で記述された名前付きプロパティをオブジェクトへ追加します。
Object.defineProperty()-
指定された記述子で記述された複数の名前付きプロパティをオブジェクトへ追加します。
Object.entries()-
指定されたオブジェクト自身の列挙可能な文字列プロパティのすべての
[key, value]の組を含む配列を返します。 Object.freeze()-
オブジェクトを凍結します。他のコードがプロパティを削除したり変更したりすることができなくなります。
Object.fromEntries()-
反復可能な
[key, value]の組から新しいオブジェクトを返します。(これはObject.entriesの逆です。) Object.getOwnPropertyDescriptor()-
オブジェクトの名前付きプロパティに対応するプロパティ記述子を返します。
Object.getOwnPropertyDescriptors()-
オブジェクト自身のすべてのプロパティの記述子を含むオブジェクトを返します。
Object.getOwnPropertyNames()-
指定したオブジェクト自身の列挙可能および列挙不可なすべてのプロパティの名前を、配列として返します。
Object.getOwnPropertySymbols()-
指定したオブジェクト上に直接存在するすべてのシンボルプロパティからなる配列を返します。