Any chance for an `Object.assignProperties` ?

Andrea Giammarchi andrea.giammarchi at gmail.com
Thu Feb 13 18:51:28 UTC 2020


The fact `assign` doesn't copy descriptors and has potential side-effects
is documented extensively though, meaning there is room for improvement, or
simply a missing native way to do that, like it was for
`getOwnPropertyDescriptors`, that following your logic should've never
landed.

But I guess I'd go with the usual "yet another micro library" approach
instead, so that at least I won't have to deal with assign shenanigans when
I mean to copy accessors too.

On Thu, Feb 13, 2020 at 7:33 PM Jordan Harband <ljharb at gmail.com> wrote:

> It seems like it’s the exact implementation you want, just for 1 object
> instead of N.
>
> Object.assign was added because versions of it were all over the web, used
> very frequently. How frequent is the pattern where people want to copy
> descriptors, such that it would deserve reification in the language?
>
> On Thu, Feb 13, 2020 at 10:23 AM Andrea Giammarchi <
> andrea.giammarchi at gmail.com> wrote:
>
>> That has nothing to do with this, right?
>>
>> ```js
>> const {assign, defineProperties, getOwnPropertyDescriptors} = Object;
>> const assignProperties = (base, ...mixins) => defineProperties(
>>   base,
>>   mixins.reduce(
>>     (descriptors, mixin) => assign(
>>       descriptors,
>>       getOwnPropertyDescriptors(mixin)
>>     ),
>>     {}
>>   )
>> );
>> ```
>>
>> On Thu, Feb 13, 2020 at 6:51 PM Jordan Harband <ljharb at gmail.com> wrote:
>>
>>> `Object.defineProperties(target,
>>> Object.getOwnPropertyDescriptors(source))`?
>>>
>>> On Thu, Feb 13, 2020 at 2:24 AM Andrea Giammarchi <
>>> andrea.giammarchi at gmail.com> wrote:
>>>
>>>> Both `Object.assign` and `{...extend}` suffer a tiny gotcha: properties
>>>> are never assigned, neither retrieved, as accessors, with side-effects too.
>>>>
>>>> Example:
>>>> ```js
>>>> const Counter = {
>>>>   _count: 0,
>>>>   get count() {
>>>>     return this._count++;
>>>>   }
>>>> };
>>>>
>>>> const incr1 = Object.assign({}, Counter);
>>>> const incr2 = {...Counter};
>>>>
>>>> console.log(
>>>>   incr1.count,    // 0
>>>>   incr2.count,    // 1
>>>>   Counter._count  // 2
>>>> );
>>>>
>>>> // functionality also compromised
>>>> console.log(incr1.count === incr1.count);
>>>> ```
>>>>
>>>> Not only most of the time this is unexpected, but there's literally no
>>>> way to pass along accessors with a similar `Object.assign` ease, even if
>>>> that's what most developers would expect (at least up to the first time
>>>> they encounter above issue).
>>>>
>>>> How about we introduce `Object.assignProperties` instead?
>>>>
>>>> A polyfill example:
>>>>
>>>> ```js
>>>> const {assign, defineProperties, getOwnPropertyDescriptors} = Object;
>>>> const assignProperties = (base, ...mixins) => defineProperties(
>>>>   base,
>>>>   mixins.reduce(
>>>>     (descriptors, mixin) => assign(
>>>>       descriptors,
>>>>       getOwnPropertyDescriptors(mixin)
>>>>     ),
>>>>     {}
>>>>   )
>>>> );
>>>> ```
>>>>
>>>> We can now use objects and mixins without side-effecting sources used
>>>> to extend, and preserving accessors in the process.
>>>>
>>>> ```js
>>>> const Counter = {
>>>>   _count: 0,
>>>>   get count() {
>>>>     return this._count++;
>>>>   }
>>>> };
>>>>
>>>> const incr1 = Object.assignProperties({}, Counter);
>>>> const incr2 = Object.assignProperties({}, Counter);
>>>>
>>>> console.log(
>>>>   incr1.count,    // 0
>>>>   incr2.count,    // 0
>>>>   Counter._count  // 0
>>>> );
>>>>
>>>> // always false: preserved functionality
>>>> console.log(incr1.count === incr1.count);
>>>> ```
>>>>
>>>> Thoughts ?
>>>> _______________________________________________
>>>> es-discuss mailing list
>>>> es-discuss at mozilla.org
>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>
>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20200213/3a1c0f0e/attachment.html>


More information about the es-discuss mailing list