Object.getOwnPropertyDescriptors(O) ? // plural

# Andrea Giammarchi (7 years ago)

I wonder if by any chance this could sneak into ES6 ... we have only singular version here: people.mozilla.org/~jorendorff/es6-draft.html#sec-object.getownpropertydescriptor

rationale The easiest way to create a shallow copy of a generic object could be:

var shallowCopy = Object.create(
  Object.getPrototypeOf(originalObject),
  Object.getOwnPropertyDescriptors(originalObject)
);

Today what we have to do this instead:

var shallowCopy = Object.create(
  Object.getPrototypeOf(originalObject),
  Object.getOwnPropertyNames(originalObject).reduce(
  function (descriptors, name) {
    descriptors[name] = Object.getOwnPropertyDescriptor(
      originalObject, name
    );
    return descriptors;
  }, {})
);

I see latter pattern as sort of unnecessary overhead that could be also much faster in core and polyfilled in the meanwhile.

Thoughts ?

Cheers

# Brandon Benvie (7 years ago)

Further rational:

  • Symmetry with defineProperty/defineProperties.
  • One of the benefits of defineProperties (and create) is that they handle errors such that the failure of any individual property doesn't necessarily fail all the remaining ones. It is, of course, possible for a developer to define their own getOwnPropertyDescriptors to also behave this way, but it's not an obvious concern and is usually overlooked
# Andrea Giammarchi (7 years ago)

actually, since Object.getOwnPropertyDescriptor accepts Symbols too as second argument, the equivalent with current ES6 would be even more prolix than that


var shallowCopy = Object.create(
  Object.getPrototypeOf(originalObject),
  Object.getOwnPropertyNames(originalObject).concat(
  Object.getOwnPropertySymbols(originalObject)
  ).reduce(function (descriptors, name) {
    descriptors[name] = Object.getOwnPropertyDescriptor(
      originalObject, name
    );
    return descriptors;
  }, {})
);

assuming Symbols will be definable through descriptors ... all this VS

var shallowCopy = Object.create(
  Object.getPrototypeOf(originalObject),
  Object.getOwnPropertyDescriptors(originalObject)
);

which I believe is a win.

# Andrea Giammarchi (7 years ago)

Brandon I take your answer as +1, thanks.

I've also "gisted" a possible/basic polyfill here: gist.github.com/WebReflection/9317065

# Andrea Giammarchi (7 years ago)

up ?

# Andrea Giammarchi (7 years ago)

Apparently this triggered an @rwaldron which seems to be super-effective

In agenda for April's meeting.

Thanks

Sent from my Windows Phone

From: C. Scott Ananian <cscott at cscott.net>

Sent: 3/4/2014 6:16 To: Andrea Giammarchi <andrea.giammarchi at gmail.com>

Cc: es-discuss at mozilla.org list <es-discuss at mozilla.org>

Subject: Re: Object.getOwnPropertyDescriptors(O) ? // plural

Have you filed a bugzilla ticket for this? That seems the best way to ensure it will get discussed at the next TC39 meeting and resolved one way or the other.

# Rick Waldron (7 years ago)

On Tue, Mar 4, 2014 at 12:30 PM, Andrea Giammarchi < andrea.giammarchi at gmail.com> wrote:

Apparently this triggered an @rwaldron which seems to be super-effective

In agenda for April's meeting.

Yep: tc39/agendas/blob/master/2014/04.md

Going to try, but it's so late in the game that I really can't promise anything--I think it's simple enough that we can get away with it. I will write up a proposed normative spec (likely based on Andrea's work) before I present, I've found that's a pretty powerful way to make a case for late additions ;)

# Rick Waldron (7 years ago)

Question: should the returned array include property descriptors for properties whose key is a symbol?

# Andrea Giammarchi (7 years ago)

yes, because Object.getOwnPropertyDescriptor(O, k) accepts both propertyName and Symbol as second argument. The plural, and to be consistent with the shallowCopy example, should return a list of both.

This is also because all descriptors returned by Object.getOwnPropertySymbols can be used same way Object.getOwnPropertyNames ... so, unless Object.defineProperty(O, k, d) does not accept k as Symbol (basically breaking this proposal via Object.create) I don't see why the plural version should not return descriptors for both kind of properties.

My 2 cents

# Rick Waldron (7 years ago)

On Tue, Mar 4, 2014 at 12:48 PM, Andrea Giammarchi < andrea.giammarchi at gmail.com> wrote:

yes, because Object.getOwnPropertyDescriptor(O, k) accepts both propertyName and Symbol as second argument. The plural, and to be consistent with the shallowCopy example, should return a list of both.

This is also because all descriptors returned by Object.getOwnPropertySymbols can be used same way Object.getOwnPropertyNames ... so, unless Object.defineProperty(O, k, d) does not accept k as Symbol (basically breaking this proposal via Object.create) I don't see why the plural version should not return descriptors for both kind of properties.

My 2 cents

Makes sense to me

# Allen Wirfs-Brock (7 years ago)

On Mar 4, 2014, at 9:34 AM, Rick Waldron wrote:

On Tue, Mar 4, 2014 at 12:30 PM, Andrea Giammarchi <andrea.giammarchi at gmail.com> wrote: Apparently this triggered an @rwaldron which seems to be super-effective

In agenda for April's meeting.

Yep: tc39/agendas/blob/master/2014/04.md

Going to try, but it's so late in the game that I really can't promise anything—I think it's simple enough that we can get away with it. I will write up a proposed normative spec (likely based on Andrea's work) before I present, I've found that's a pretty powerful way to make a case for late additions ;)

I like this cloning idiom, but I don't see why we would consider this for ES6, it isn't something that is critical or can't be implemented via ES code. It would be much more appropriate to queue it up for the 2015 train.

ES6: let's wrap this sucker up!

# Andrea Giammarchi (7 years ago)

I mixed up ... sorry, let me recap:

  1. Object.getOwnPropertyNames(O) list of properties and Object.getOwnPropertySymbols(O) list of Symbols can be both used, per each item of each list, with Object.getOwnPropertyDescriptor(O, propertyOrSymbol)
  2. Object.getOwnPropertyDescriptor(O, propertyOrSymbol) accepts, as second argument, only as a property name or a Symbol, otherwise it throws as specified here
  3. accordingly, the most meaningful collection as Object of descriptors the proposed plural Object.getOwnPropertyDescriptors(O) should return is a collection that includes descriptors for both properties and Symbols

I hope this makes sense. Thanks again Rick for, at least, trying and helping out with this.

# Rick Waldron (7 years ago)

On Tue, Mar 4, 2014 at 1:03 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:

On Mar 4, 2014, at 9:34 AM, Rick Waldron wrote:

On Tue, Mar 4, 2014 at 12:30 PM, Andrea Giammarchi < andrea.giammarchi at gmail.com> wrote:

Apparently this triggered an @rwaldron which seems to be super-effective

In agenda for April's meeting.

Yep: tc39/agendas/blob/master/2014/04.md

Going to try, but it's so late in the game that I really can't promise anything--I think it's simple enough that we can get away with it. I will write up a proposed normative spec (likely based on Andrea's work) before I present, I've found that's a pretty powerful way to make a case for late additions ;)

I like this cloning idiom, but I don't see why we would consider this for ES6, it isn't something that is critical or can't be implemented via ES code. It would be much more appropriate to queue it up for the 2015 train.

ES6: let's wrap this sucker up!

I agree with this, but time permitting I want to at least get something presented.

# Andrea Giammarchi (7 years ago)

this boilerplate is error prone and prolix plus it cannot be optimized in core so it's also very slow.

With the introduction of classes, Symbols, and all ES6 new entries, I feel like the for(var key in object) loop is dead but developers have no way to clone objects in the right way and in one shot possibly optimized/optimizable in core.

I understand it's very late but I wonder, with Rick help, if a "brutal" copy and paste of a very simple spec that feels natural as complement of the singular Object.getOwnPropertyDescriptor(O, k) would be considered ... I certainly don't want waste Rick time with this, neither yours, of course.

So, in case ES6 is not an option, I wonder if we could have a slot in ES7 so that the polyfill could be adopted and developers life made easier.

I really hope I didn't need in ES6 to write this:

var shallowCopy = Object.create(
  Object.getPrototypeOf(originalObject),
  Object.getOwnPropertyNames(originalObject).concat(
  Object.getOwnPropertySymbols(originalObject)
  ).reduce(function (descriptors, name) {
    descriptors[name] = Object.getOwnPropertyDescriptor(
      originalObject, name
    );
    return descriptors;
  }, {})
);

Thanks in advance for any outcome.

# Allen Wirfs-Brock (7 years ago)

On Mar 4, 2014, at 10:17 AM, Rick Waldron wrote:

I like this cloning idiom, but I don't see why we would consider this for ES6, it isn't something that is critical or can't be implemented via ES code. It would be much more appropriate to queue it up for the 2015 train.

ES6: let's wrap this sucker up!

I agree with this, but time permitting I want to at least get something presented.

Presenting is cool, actually necessary to get in on the next train. But unless something is really critical, let's not try to squeeze it into ES6

# Andrea Giammarchi (7 years ago)

Allen, as developer, being unable to shallow-copy in JavaScript for other N years is actually critical.

Luckily it's not so difficult to polyfill but if you have Rick presenting something like this I really hope there would be an exception or at least a remote possibility it'd squeeze in :-)

I'd be very happy in any case if considered for the future.

Once again, a huge thanks for Rick effort and André too helping with the simplified yet more accurate version of the proposal.

Best

# Rick Waldron (7 years ago)

On Tue, Mar 4, 2014 at 2:40 PM, Andrea Giammarchi < andrea.giammarchi at gmail.com> wrote:

Allen, as developer, being unable to shallow-copy in JavaScript for other N years is actually critical.

Luckily it's not so difficult to polyfill but if you have Rick presenting something like this I really hope there would be an exception or at least a remote possibility it'd squeeze in :-)

I'd be very happy in any case if considered for the future.

Once again, a huge thanks for Rick effort and André too helping with the simplified yet more accurate version of the proposal.

I've updated the agenda to use this version--my draft design that returned an array was "meh", but I couldn't put my finger on why, this addresses that problem.

# Andrea Giammarchi (7 years ago)

"thing" ... no "things", just this one ... pliiiiiiiiiz :-)

Also please note that this proposal simplifies Object.assign(target, source) too since latter one is basically:

Object.defineProperties(
  target,
  Object.getOwnPropertyDescriptors(source)
);

So, in order of priority or what is needed the most, I think with Object.getOwnPropertyDescriptors(O) we can solve more than Object.assign(target, source) but bear in mind I am not pushing back the latter one anyhow.

IMO this proposal is just very, very related to ES6 changes due Symbols but it should have probably been in ES5 too because there was defined Object.getOwnPropertyDescriptor which has been indeed upgraded to accept ES6 Symbols too.

The spec as it is kinda a no-brainer, ready for copy and paste once reviewed, and simple enough I believe the implementation is straight forward, and I won't mind pushing a patch for V8 to start playing with.

All this, of course, if everyone agrees and there is a consensus at the next meeting after Rick presentation.

Best

# Claude Pache (7 years ago)

Le 5 mars 2014 à 00:18, Andrea Giammarchi <andrea.giammarchi at gmail.com> a écrit :

Also please note that this proposal simplifies Object.assign(target, source) too since latter one is basically:

Object.defineProperties(
  target,
  Object.getOwnPropertyDescriptors(source)
);

No. Object.assign (1) uses the semantics of the assignment operator = (for example, it makes a difference in case of setters), and (2) copies only enumerable properties. Did you think about Object.mixin?

# Andrea Giammarchi (7 years ago)

You are right, I've realized it after posting ... Object.assign(target, source) via Get and Put is basically the equivalent of a classic for/in with hasOwnProperty check ... well, once again, in ES6 Object.getOwnPropertyDescriptors(O) seems to be a solution for other cases too (shallow copy of properties, shallow clone, not just for/in) plus yes, Object.mixin(target, source) might be simplified as well via this proposal, that's a good point ... so 3 problems solved at once! :-)

# Tom Van Cutsem (7 years ago)

Object.getOwnPropertyDescriptors(obj) makes sense to me. As noted somewhere upstream, it's symmetrical to Object.defineProperties.

When I designed traits.js, which was heavily based on property descriptors, I even added it to the library's public API, under the slightly shorter name Object.getOwnProperties(obj), cf. traitsjs.org/api.html

Brendan asked me whether Object.getOwnPropertyDescriptors would necessitate a derived trap for proxies. I think the answer is no, just like Object.defineProperties(proxy) triggers just the proxy's getOwnPropertyNames trap, and then the defineProperty trap for each property, Object.getOwnPropertyDescriptors(proxy) would trigger the getOwnPropertyNames trap, followed by calls to the getOwnPropertyDescriptor trap for each individual property.

Cheers, Tom

2014-03-05 1:38 GMT+01:00 Andrea Giammarchi <andrea.giammarchi at gmail.com>:

# C. Scott Ananian (7 years ago)

On Wed, Mar 5, 2014 at 1:39 PM, Tom Van Cutsem <tomvc.be at gmail.com> wrote:

Object.getOwnPropertyDescriptors(proxy) would trigger the getOwnPropertyNames trap, followed by calls to the getOwnPropertyDescriptor trap for each individual property.

[[OwnPropertyKeys]], ownKeys trap.

# Andrea Giammarchi (7 years ago)

Thanks for clarification Tom, I've also added the main two features this method in the first gist I've posted but here a quick recap:


// for shallow object copy
var shallowCopy = Object.create(
  Object.getPrototypeOf(origin),
  Object.getOwnPropertyDescriptors(origin)
);

// for traits / mixin
Object.defineProperties(
  target,
  Object.getOwnPropertyDescriptors(origin)
);

// respecting ES5 symmetry
Object.defineProperty(O, name, descriptor);
  descriptor as Object.getOwnPropertyDescriptor(O, name)


Object.defineProperties(O, descriptors);
  descriptors as Object.getOwnPropertyDescriptors(O)

Hope this one help presenting the what, the why, and the how.

Best

# Tom Van Cutsem (7 years ago)

2014-03-05 20:11 GMT+01:00 C. Scott Ananian <ecmascript at cscott.net>:

On Wed, Mar 5, 2014 at 1:39 PM, Tom Van Cutsem <tomvc.be at gmail.com> wrote:

Object.getOwnPropertyDescriptors(proxy) would trigger the getOwnPropertyNames trap, followed by calls to the getOwnPropertyDescriptor trap for each individual property.

[[OwnPropertyKeys]], ownKeys trap.

Yes, according to the current draft spec. I have a pending discussion with Allen that we actually need to reintroduce a [[GetOwnPropertyNames]] internal method / getOwnPropertyNames trap, as the ownKeys trap doesn't do any invariant checking, which is needed for a reliable Object.isFrozen test.

, Tom

# C. Scott Ananian (7 years ago)

If you use a getOwnPropertyNames trap, then you also need a getOwnPropertySymbols trap to implement getOwnPropertyDescriptors.

# Andrea Giammarchi (7 years ago)

I would rephrase into this:

if you need a getOwnPropertyNames trap, you might need for consistency a getOwnPropertySymbols independently from getOwnPropertyDescriptors since these methods are already available.

I also would like to add a couple of links to support the fact getOwnPropertyDescriptors is needed, and has been asked for, since quite a while: this was 11th of November 2011 ... I didn't know it, and now that I do I wonder why this has been post-poned for so long and never discussed again.

esdiscuss/2011-November/018275

Best

# André Bargull (7 years ago)

I would rephrase into this:

if you need a getOwnPropertyNames trap, you might need for consistency a getOwnPropertySymbols independently from getOwnPropertyDescriptors since these methods are already available.

While it shares the same name with Object.getOwnPropertyNames(), this getOwnPropertyNames trap is supposed to return string and symbol keyed properties, see esdiscuss.org/topic/ownpropertykeys .

I also would like to add a couple of links to support the fact getOwnPropertyDescriptors is needed, and has been asked for, since quite a while: this was 11th of November 2011 ... I didn't know it, and now that I do I wonder why this has been post-poned for so long and never discussed again.

esdiscuss/2011-November/018275

Or even earlier, strawman:extended_object_api from 2010.

# Brendan Eich (7 years ago)

André Bargull <mailto:andre.bargull at udo.edu> March 6, 2014 at 1:21 PM

I would rephrase into this:

if you need a getOwnPropertyNames trap, you might need for consistency a getOwnPropertySymbols independently from getOwnPropertyDescriptors since these methods are already available.

While it shares the same name with Object.getOwnPropertyNames(), this getOwnPropertyNames trap is supposed to return string and symbol keyed properties, see esdiscuss.org/topic/ownpropertykeys .

Should the trap end in Keys not Names?

# Andrea Giammarchi (7 years ago)

Thanks Andrew, I wonder if I should update the proposed spec somehow, but I thought as it is combines both Names and Symbols as abstract.

Please let me know and I'll update.

Best

# Andrea Giammarchi (7 years ago)

autocomplete misspelled Andre' , apologies

# André Bargull (7 years ago)

On 3/6/2014 10:24 PM, Brendan Eich wrote:

André Bargull <mailto:andre.bargull at udo.edu> March 6, 2014 at 1:21 PM

I would rephrase into this:

if you need a getOwnPropertyNames trap, you might need for consistency a getOwnPropertySymbols independently from getOwnPropertyDescriptors since these methods are already available.

While it shares the same name with Object.getOwnPropertyNames(), this getOwnPropertyNames trap is supposed to return string and symbol keyed properties, see esdiscuss.org/topic/ownpropertykeys .

Should the trap end in Keys not Names?

/be

Only if [[OwnPropertyKeys]] gets renamed to something else, because having both [[GetOwnPropertyKeys]] and [[OwnPropertyKeys]] seems unnecessarily confusing.

# André Bargull (7 years ago)

On 3/6/2014 11:35 PM, Andrea Giammarchi wrote:

autocomplete misspelled Andre' , apologies

No worries! :-)

On Thu, Mar 6, 2014 at 2:34 PM, Andrea Giammarchi <andrea.giammarchi at gmail.com <mailto:andrea.giammarchi at gmail.com>> wrote:

Thanks Andrew, I wonder if I should update the proposed spec
somehow, but I thought as it is combines both Names and Symbols as
abstract.

You mean this proposal gist.github.com/WebReflection/9353781, right? It does not need to be changed, because the [[OwnPropertyKeys]] internal method returns string and symbol valued property keys. Or to be more correct, it returns string and symbol valued property keys for ordinary objects. Proxy objects are currently allowed to return any value from their [[OwnPropertyKeys]] internal method, because the result value of the "ownKeys" trap is not checked at all. (Except of a simple type check to ensure it is an object.)

The proposed [[GetOwnPropertyNames]] internal method is supposed to be a more restrictive version of [[OwnPropertyKeys]] to ensure Proxy objects don't lie about their properties. This is only required for certain integrity critical methods, like for example Object.isFrozen().

# Andrea Giammarchi (7 years ago)

got it, thanks again.

# C. Scott Ananian (7 years ago)

On Thu, Mar 6, 2014 at 6:31 PM, André Bargull <andre.bargull at udo.edu> wrote:

On 3/6/2014 11:35 PM, Andrea Giammarchi wrote: The proposed [[GetOwnPropertyNames]] internal method is supposed to be a more restrictive version of [[OwnPropertyKeys]] to ensure Proxy objects don't lie about their properties.

[[SafeOwnPropertyKeys]] or [[CheckedOwnPropertyKeys]] seems like a more accurate and less confusing name, since it returns keys not names.

# Tom Van Cutsem (7 years ago)

2014-03-07 0:51 GMT+01:00 C. Scott Ananian <ecmascript at cscott.net>:

On Thu, Mar 6, 2014 at 6:31 PM, André Bargull <andre.bargull at udo.edu> wrote:

On 3/6/2014 11:35 PM, Andrea Giammarchi wrote: The proposed [[GetOwnPropertyNames]] internal method is supposed to be a more restrictive version of [[OwnPropertyKeys]] to ensure Proxy objects don't lie about their properties.

[[SafeOwnPropertyKeys]] or [[CheckedOwnPropertyKeys]] seems like a more accurate and less confusing name, since it returns keys not names.

The result is only "checked" for proxies, but the name of internal methods should make sense for all types of objects.

From an API point of view, the more significant difference may be that [[OwnPropertyKeys]] returns an iterable, while [[CheckedOwnPropertyKeys]] would return an array of strings and symbols. I don't think there is currently a good naming convention to distinguish things that return an iterable versus things that return an array.

I searched the spec for all clients of [[OwnPropertyKeys]], they are:

Object.assign(target, source) // to iterate over all own props (strings and symbols) of source Object.keys(O) // to construct array of strings (of enumerable properties) Reflect.ownKeys(O) // to get iterator over strings and symbols

// the following should be reliable primitives, thus should use the "checked" version that returns an array: Object.getOwnPropertyNames(O) // to construct array of strings Object.getOwnPropertySymbols(O) // to construct array of symbols Object.{freeze,seal}(O) // to reliably redefine all own props Object.{isFrozen,isSealed}(O) // to reliably test all own props

Given that most of the functions that use [[OwnPropertyKeys]] need to either construct an array anyway, or want reliable results, I wonder whether we shouldn't just change [[OwnPropertyKeys]] to include the checks and return an array instead of an iterable. That way we avoid having two internal methods that do more or less the same thing.

# C. Scott Ananian (7 years ago)

I was also a bit puzzled by the iterator return value. I expected that it would handle mutation (adding new properties) during traveral the way that the Map and Set iterators do. I was surprised to see that all the users turned the iterator into an array; none seemed to handle concurrent mutation. So why not return an Array?

# Brendan Eich (7 years ago)

Tom Van Cutsem wrote:

Given that most of the functions that use [[OwnPropertyKeys]] need to either construct an array anyway, or want reliable results, I wonder whether we shouldn't just change [[OwnPropertyKeys]] to include the checks and return an array instead of an iterable. That way we avoid having two internal methods that do more or less the same thing.

+1.