Any chance for an `Object.assignProperties` ?
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source))
?
`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/24c50c71/attachment.html>
That has nothing to do with this, right?
const {assign, defineProperties, getOwnPropertyDescriptors} = Object;
const assignProperties = (base, ...mixins) => defineProperties(
base,
mixins.reduce(
(descriptors, mixin) => assign(
descriptors,
getOwnPropertyDescriptors(mixin)
),
{}
)
);
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/4f560003/attachment.html>
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?
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/e5d19fce/attachment-0001.html>
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.
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>
Anyway, if anyone is interested, I've published the assign-properties
module [1]
Anyway, if anyone is interested, I've published the `assign-properties` module [1] [1] https://github.com/WebReflection/assign-properties#readme On Thu, Feb 13, 2020 at 7:51 PM Andrea Giammarchi < andrea.giammarchi at gmail.com> wrote: > 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/692c0bcf/attachment-0001.html>
Both
Object.assign
and{...extend}
suffer a tiny gotcha: properties are never assigned, neither retrieved, as accessors, with side-effects too.Example:
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:
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.
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 ?