Object.getOwnPropertyDescriptors()
This chapter explains the ECMAScript 2017 feature “Object.getOwnPropertyDescriptors()
” by Jordan Harband and Andrea Giammarchi.
Object.getOwnPropertyDescriptors(obj)
returns the property descriptors of all own properties of obj
, in an Array:
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)
accepts an object obj
and returns an object result
:
obj
, it adds a property to result
whose key is the same and whose value is the the former property’s descriptor.Property descriptors describe the attributes of a property (its value, whether it is writable, etc.). For more information, consult Sect. “Property Attributes and Property Descriptors” in “Speaking JavaScript”.
This is an example of using 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 } }
This is how you would implement Object.getOwnPropertyDescriptors()
:
function
getOwnPropertyDescriptors
(
obj
)
{
const
result
=
{};
for
(
let
key
of
Reflect
.
ownKeys
(
obj
))
{
result
[
key
]
=
Object
.
getOwnPropertyDescriptor
(
obj
,
key
);
}
return
result
;
}
Object.getOwnPropertyDescriptors()
Since ES6, JavaScript already has a tool method for copying properties: Object.assign()
. However, this method uses simple get and set operations to copy a property whose key is key
:
const
value
=
source
[
key
];
// get
target
[
key
]
=
value
;
// set
That means that it doesn’t properly copy properties with non-default attributes (getters, setters, non-writable properties, etc.). The following example illustrates this limitation. The object source
has a setter whose key is foo
:
const
source
=
{
set
foo
(
value
)
{
console
.
log
(
value
);
}
};
console
.
log
(
Object
.
getOwnPropertyDescriptor
(
source
,
'foo'
));
// { get: undefined,
// set: [Function: foo],
// enumerable: true,
// configurable: true }
Using Object.assign()
to copy property foo
to object target
fails:
const
target1
=
{};
Object
.
assign
(
target1
,
source
);
console
.
log
(
Object
.
getOwnPropertyDescriptor
(
target1
,
'foo'
));
// { value: undefined,
// writable: true,
// enumerable: true,
// configurable: true }
Fortunately, using Object.getOwnPropertyDescriptors()
together with Object.defineProperties()
works:
const
target2
=
{};
Object
.
defineProperties
(
target2
,
Object
.
getOwnPropertyDescriptors
(
source
));
console
.
log
(
Object
.
getOwnPropertyDescriptor
(
target2
,
'foo'
));
// { get: undefined,
// set: [Function: foo],
// enumerable: true,
// configurable: true }
Shallow cloning is similar to copying properties, which is why Object.getOwnPropertyDescriptors()
is a good choice here, too.
This time, we use Object.create()
that has two parameters:
Object.getOwnPropertyDescriptors()
.
const
clone
=
Object
.
create
(
Object
.
getPrototypeOf
(
obj
),
Object
.
getOwnPropertyDescriptors
(
obj
));
The syntactically nicest way of using an object literal to create an object with an arbitrary prototype prot
is to use the special property __proto__
:
const
obj
=
{
__proto__
:
prot
,
foo
:
123
,
};
Alas, that feature is only guaranteed to be there in browsers. The common work-around is Object.create()
and assignment:
const
obj
=
Object
.
create
(
prot
);
obj
.
foo
=
123
;
But you can also use Object.getOwnPropertyDescriptors()
:
const
obj
=
Object
.
create
(
prot
,
Object
.
getOwnPropertyDescriptors
({
foo
:
123
,
})
);
Another alternative is Object.assign()
:
const
obj
=
Object
.
assign
(
Object
.
create
(
prot
),
{
foo
:
123
,
}
);
super
A method that uses super
is firmly connected with its home object (the object it is stored in). There is currently no way to copy or move such a method to a different object.