Object.getOwnPropertyDescriptors()
この章では、「Object.getOwnPropertyDescriptors()
」というJordan HarbandとAndrea GiammarchiによるECMAScript 2017の機能について説明します。
Object.getOwnPropertyDescriptors(obj)
は、配列として、obj
のすべての所有プロパティのプロパティ記述子を返します。
const
obj
=
{
[
Symbol
(
'foo'
)]
:
123
,
get
bar
()
{
return
'abc'
},
};
console
.
log
(
Object
.
getOwnPropertyDescriptors
(
obj
));
// Output:
// { [Symbol('foo')]:
// { value: 123,
// writable: true,
// enumerable: true,
// configurable: true },
// bar:
// { get: [Function: bar],
// set: undefined,
// enumerable: true,
// configurable: true } }
Object.getOwnPropertyDescriptors()
Object.getOwnPropertyDescriptors(obj)
はオブジェクトobj
を受け取り、オブジェクトresult
を返します。
obj
の所有(継承していない)プロパティごとに、キーが同じで、値がそのプロパティの記述子であるプロパティをresult
に追加します。プロパティ記述子は、プロパティの属性(値、書き込み可能かどうかなど)を記述します。詳しくは「Exploring JavaScript」の「プロパティ属性とプロパティ記述子」セクションを参照してください。
Object.getOwnPropertyDescriptors()
を使う例です。
const
obj
=
{
[
Symbol
(
'foo'
)]
:
123
,
get
bar
()
{
return
'abc'
},
};
console
.
log
(
Object
.
getOwnPropertyDescriptors
(
obj
));
// Output:
// { [Symbol('foo')]:
// { value: 123,
// writable: true,
// enumerable: true,
// configurable: true },
// bar:
// { get: [Function: bar],
// set: undefined,
// enumerable: true,
// configurable: true } }
Object.getOwnPropertyDescriptors()
を実装する方法は次のとおりです。
function
getOwnPropertyDescriptors
(
obj
)
{
const
result
=
{};
for
(
let
key
of
Reflect
.
ownKeys
(
obj
))
{
result
[
key
]
=
Object
.
getOwnPropertyDescriptor
(
obj
,
key
);
}
return
result
;
}
Object.getOwnPropertyDescriptors()
のユースケース ES6以降、JavaScriptにはすでにプロパティをコピーするためのツールメソッドObject.assign()
があります。ただし、このメソッドは単純なgetとsetの操作を使用して、キーがkey
のプロパティをコピーします。
const
value
=
source
[
key
];
// get
target
[
key
]
=
value
;
// set
それは、デフォルト以外の属性(ゲッター、セッター、書き込み不可のプロパティなど)を持つプロパティを正しくコピーしないことを意味します。次の例はこの制限を説明しています。オブジェクトsource
にはキーがfoo
のセッターがあります。
const
source
=
{
set
foo
(
value
)
{
console
.
log
(
value
);
}
};
console
.
log
(
Object
.
getOwnPropertyDescriptor
(
source
,
'foo'
));
// { get: undefined,
// set: [Function: foo],
// enumerable: true,
// configurable: true }
Object.assign()
を使用してプロパティfoo
をオブジェクトtarget
にコピーしようとすると失敗します。
const
target1
=
{};
Object
.
assign
(
target1
,
source
);
console
.
log
(
Object
.
getOwnPropertyDescriptor
(
target1
,
'foo'
));
// { value: undefined,
// writable: true,
// enumerable: true,
// configurable: true }
幸い、Object.getOwnPropertyDescriptors()
とObject.defineProperties()
を一緒に使用すると機能します。
const
target2
=
{};
Object
.
defineProperties
(
target2
,
Object
.
getOwnPropertyDescriptors
(
source
));
console
.
log
(
Object
.
getOwnPropertyDescriptor
(
target2
,
'foo'
));
// { get: undefined,
// set: [Function: foo],
// enumerable: true,
// configurable: true }
シャロー複製はプロパティのコピーに似ているため、Object.getOwnPropertyDescriptors()
もまた、ここでも適した選択肢です。
今回は、2つのパラメータを持つObject.create()
を使用します。
Object.getOwnPropertyDescriptors()
によって返されるものと同じプロパティ記述子のコレクションです。
const
clone
=
Object
.
create
(
Object
.
getPrototypeOf
(
obj
),
Object
.
getOwnPropertyDescriptors
(
obj
));
任意のプロトタイプprot
を持つオブジェクトを作成するためのオブジェクトリテラルを使用する構文的に最も優れた方法は、特殊プロパティ__proto__
を使用することです。
const
obj
=
{
__proto__
:
prot
,
foo
:
123
,
};
残念なことに、その機能はブラウザでのみ保証されています。一般的な回避策はObject.create()
と代入です。
const
obj
=
Object
.
create
(
prot
);
obj
.
foo
=
123
;
また、Object.getOwnPropertyDescriptors()
を使用することもできます。
const
obj
=
Object
.
create
(
prot
,
Object
.
getOwnPropertyDescriptors
({
foo
:
123
,
})
);
もう1つの選択肢はObject.assign()
です。
const
obj
=
Object
.
assign
(
Object
.
create
(
prot
),
{
foo
:
123
,
}
);
super
を使用するメソッドのコピー super
を使用する方法は、そのホームオブジェクト(それが格納されているオブジェクト)に密接に結びつけられます。そのようなメソッドを別のオブジェクトにコピーまたは移動する方法はありません。