JavaScriptのObject.getOwnPropertyDescriptor
メソッドは、指定されたオブジェクトの特定の自身のプロパティ(継承されたプロパティではない)のプロパティディスクリプタを取得するために使用されます。
プロパティディスクリプタとは、プロパティの値
だけでなく、そのプロパティが書き込み可能か
(writable
)、列挙可能か
(enumerable
)、設定変更可能か
(configurable
)、あるいはゲッター/セッターを持つか
(get
/set
)といった詳細な属性情報を含むオブジェクトです。
このメソッドは、オブジェクトの内部的な構造を調べたり、Object.defineProperty
やObject.defineProperties
で設定されたプロパティの挙動を確認したりする際に便利です。
この記事では、Object.getOwnPropertyDescriptor
メソッドの基本的な使い方、引数、戻り値、主要な使用例、そして使用する際の重要な注意点について解説します。
Object.getOwnPropertyDescriptorメソッドの基本的な構文
Object.getOwnPropertyDescriptor
メソッドの基本的な構文は以下の通りです。
Object.getOwnPropertyDescriptor(obj, propName)
obj
: 必須。プロパティディスクリプタを取得したいオブジェクトです。propName
: 必須。ディスクリプタを取得したいプロパティの名前(文字列またはシンボル)です。
引数1(obj)
- 必須です。
- プロパティディスクリプタを取得したいオブジェクトを指定します。
null
またはundefined
を渡すとTypeError
が発生します。
引数2(propName)
- 必須です。
- ディスクリプタを取得したいプロパティの名前を文字列またはシンボルで指定します。
Object.getOwnPropertyDescriptorの戻り値
指定されたプロパティのプロパティディスクリプタオブジェクトが返されます。
プロパティが存在しない場合はundefined
が返されます。
プロパティディスクリプタの確認
Object.getOwnPropertyDescriptor
が返すプロパティディスクリプタは、以下の属性のいずれかまたはすべてを含みます。
1. データディスクリプタ (Data Descriptor)
プロパティが直接値を持つ場合。
value
: プロパティの実際の値。writable
:true
の場合、value
を変更できる。enumerable
:true
の場合、for...in
ループやObject.keys()
で列挙できる。configurable
:true
の場合、プロパティのディスクリプタを変更したり、プロパティを削除したりできる。
2. アクセサディスクリプタ (Accessor Descriptor)
プロパティがゲッター/セッター関数を持つ場合。
get
: ゲッター関数。プロパティが読み取られたときに呼び出される。set
: セッター関数。プロパティが設定されたときに呼び出される。enumerable
:true
の場合、列挙できる。configurable
:true
の場合、設定変更・削除できる。
注意
データディスクリプタとアクセサディスクリプタの属性を同時に持つことはありません。
Object.getOwnPropertyDescriptorメソッドを使ってみる
実際にObject.getOwnPropertyDescriptor
メソッドを使って、プロパティの属性を確認してみます。
例1:通常のデータプロパティのディスクリプタを取得する
通常のプロパティ代入で作成されたプロパティのデフォルト属性を確認します。
const user = {
name: 'Alice',
age: 30
};
const nameDescriptor = Object.getOwnPropertyDescriptor(user, 'name');
console.log("nameプロパティのディスクリプタ:", nameDescriptor);
/*
出力:
nameプロパティのディスクリプタ: {
value: 'Alice',
writable: true,
enumerable: true,
configurable: true
}
*/
const ageDescriptor = Object.getOwnPropertyDescriptor(user, 'age');
console.log("ageプロパティのディスクリプタ:", ageDescriptor);
/*
出力:
ageプロパティのディスクリプタ: {
value: 30,
writable: true,
enumerable: true,
configurable: true
}
*/
name
・age
プロパティを持っているuser
オブジェクトを作成しました。
その次の処理でObject.getOwnPropertyDescriptor
メソッドを使って、name
プロパティのディスクリプタを取得して出力しています。
age
プロパティも同様に取得して出力しました。
確認してみると通常のプロパティは、デフォルトでwritable: true
, enumerable: true
, configurable: true
であることがわかります。
例2:Object.definePropertyで定義されたプロパティのディスクリプタを取得する
Object.defineProperty
で属性を明示的に設定したプロパティのディスクリプタを確認します。
"use strict";
const config = {};
Object.defineProperty(config, 'version', {
value: '1.0.0',
writable: false, // 変更不可
enumerable: false, // 列挙不可
configurable: false // 削除・再設定不可
});
const versionDescriptor = Object.getOwnPropertyDescriptor(config, 'version');
console.log("versionプロパティのディスクリプタ:", versionDescriptor);
/*
出力:
versionプロパティのディスクリプタ: {
value: '1.0.0',
writable: false,
enumerable: false,
configurable: false
}
*/
最初にconfig
オブジェクトを作成しています。
次の処理でObject.defineProperty
を使ってversion
プロパティを追加しています。
それぞれの属性をfalse
に設定しました。
そして、その次の処理でディスクリプタを取得して出力しました。
version
プロパティの属性が、Object.defineProperty
で設定した通りになっていることが確認できます。
例3:ゲッター/セッタープロパティのディスクリプタを取得する
アクセサディスクリプタを持つプロパティの情報を確認します。
const circle = {
_radius: 0
};
Object.defineProperty(circle, 'radius', {
get: function() { return this._radius; },
set: function(newRadius) { this._radius = newRadius; },
enumerable: true,
configurable: true
});
const radiusDescriptor = Object.getOwnPropertyDescriptor(circle, 'radius');
console.log("radiusプロパティのディスクリプタ:", radiusDescriptor);
/*
出力:
radiusプロパティのディスクリプタ: {
get: [Function: get], // ゲッター関数
set: [Function: set], // セッター関数
enumerable: true,
configurable: true
}
*/
circle
オブジェクトを作成して、次の処理でradius
プロパティを追加しました。
radius
プロパティには、get
とset
を持っているプロパティです。
次の処理でObject.getOwnPropertyDescriptor
を使用して、radius
プロパティを取得しています。
出力して確認するとradius
プロパティがvalue
やwritable
ではなく、get
とset
を持つアクセサディスクリプタであることがわかります。
例4:存在しないプロパティや継承されたプロパティの場合
Object.getOwnPropertyDescriptor
は、存在しないプロパティや継承されたプロパティに対しては undefined
を返します。
const animal = {
eats: true
};
const rabbit = Object.create(animal);
rabbit.jumps = true;
// 存在しないプロパティ
const nonExistentDescriptor = Object.getOwnPropertyDescriptor(rabbit, 'color');
console.log("存在しないプロパティのディスクリプタ:", nonExistentDescriptor); // 出力: undefined
// 継承されたプロパティ
console.log(rabbit.eats); // true
const inheritedDescriptor = Object.getOwnPropertyDescriptor(rabbit, 'eats');
console.log("継承されたプロパティのディスクリプタ:", inheritedDescriptor); // 出力: undefined
// eats は rabbit のプロトタイプである animal に存在するため、undefined が返される。
// animal の eats プロパティのディスクリプタを取得するには、Object.getOwnPropertyDescriptor(animal, 'eats') を使う必要がある。
最初にanimal
オブジェクトを作成しています。
そのあとにanimal
オブジェクトをプロトタイプとして使用して、rabbit
オブジェクトを作成しました。
rabbit
のcolor
プロパティにアクセスしようとしていますが、存在しないためundefined
が返ります。
次にeats
プロパティは存在していますが、これは継承されたプロパティです。
そのためrabbit
自身のプロパティとしては存在せずundefined
が返されます。
Object.getOwnPropertyDescriptorを使う際の注意点
Object.getOwnPropertyDescriptorを使うときの注意点です。
自身のプロパティのみを対象とする
最も重要な注意点です。
プロトタイプチェーンを通じてアクセスできる継承されたプロパティのディスクリプタは取得できません。
あくまでオブジェクト自身が直接持つプロパティのみが対象です。
存在しない場合はundefinedを返す
プロパティが存在しない場合、エラーではなく undefined
が返されます。
この戻り値を適切にチェックする必要があります。
nullまたはundefinedのオブジェクト引数
Object.getOwnPropertyDescriptor(null, 'prop')
やObject.getOwnPropertyDescriptor(undefined, 'prop')
を呼び出すとTypeError
が発生します。
Object.getOwnPropertyDescriptors
Object.getOwnPropertyDescriptor(obj, propName)
: 単一の指定された自身のプロパティのディスクリプタを返します。Object.getOwnPropertyDescriptors(obj)
: オブジェクトのすべての自身のプロパティのディスクリプタを含む新しいオブジェクトを返します。複数のプロパティの情報を一度に取得したい場合に便利です。
const myObj = { a: 1, b: 2 };
console.log(Object.getOwnPropertyDescriptor(myObj, 'a')); // { value: 1, ... }
console.log(Object.getOwnPropertyDescriptors(myObj)); // { a: { value: 1, ... }, b: { value: 2, ... } }
まとめ
JavaScriptのObject.getOwnPropertyDescriptor
メソッドは、オブジェクトの特定の自身のプロパティに関する詳細な属性情報(プロパティディスクリプタ)を取得するための強力なツールです。
プロパティが書き込み可能か、列挙可能か、ゲッター/セッターを持つかなどをプログラムで確認したい場合に便利です。
自身のプロパティのみを対象とすること、存在しない場合は undefined
を返すこと、そしてObject.getOwnPropertyDescriptors
との使い分けを理解して使用することが不可欠です。
これらのポイントを踏まえ、Object.getOwnPropertyDescriptor
を効果的に活用し、JavaScriptアプリケーションの堅牢性と柔軟性を高めましょう。
コメント