7

I stumbled upon code similar to this in modern JavaScript:

let obj = {
  data: {number: 9},
  set prop(p) {
    this.data = p;
  },
  get prop() {
    return this.data;
  }
};

obj = Object.assign({}, obj, {
  data: {number: 2}
});

console.log('obj.data === obj.prop ', obj.data === obj.prop);
console.log('obj.data.number === obj.prop.number ', obj.data.number === obj.prop.number);

Any modification is done outside of the computed property, as if there were none.

I was expecting the computed property to still exist.

Is there a way to preserve the computed property after a call to Object.assign? Thanks.

Boann
  • 48,794
  • 16
  • 117
  • 146
Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
  • 2
    The whole point of object assign is you are creating a new object, and not a reference to the original. What is your expected output in this example? – SpeedOfRound Mar 22 '19 at 19:50
  • I would expect the property (the actual get and set) to be assign to the new object, calling the property on the new one and getting/setting though the new obj.data. I mean, conceptually they are both the same object type? – Guillaume Racicot Mar 22 '19 at 19:52
  • 1
    They are the same object "type" but you are using ===, no two objects will be evaluate to equal here, even if their contents are the same, unless one is referencing the original – SpeedOfRound Mar 22 '19 at 19:55
  • From your code: obj.data = {number: 2}, obj.prop = {number: 9}, thus obj.data != obj.prop – lracicot Mar 22 '19 at 19:55
  • 1
    @Iracicot Even if number was 9 in both of them, they would still evaluate to false – SpeedOfRound Mar 22 '19 at 19:56
  • @adiga I went ahead and flagged this for you – Steven Stark Mar 22 '19 at 20:03

2 Answers2

6

If you look at the result of the new object created by object.assign you will see that it no longer has getter/setter, but has a property prop. object.assign doesn't copy the getter/setter functions over but instead calls [[get]] and makes a new property.

MDN describes it:

It uses [[Get]] on the source and [[Set]] on the target, so it will invoke getters and setters. Therefore it assigns properties versus just copying or defining new properties. This may make it unsuitable for merging new properties into a prototype if the merge sources contain getters.

So assign() merges an object with a prop property together with an object with a data property and you get both:

let obj = {
  data: {
    number: 9
  },

  set prop(p) {
    this.data = p;
  },

  get prop() {
    return this.data;
  }

};

obj = Object.assign({}, obj, {
  data: {
    number: 2
  }
});

// it has a data and a prop property -- they are not the same:
console.log(obj)
Mark
  • 90,562
  • 7
  • 108
  • 148
  • Good thanks. But then I still have to find a way to keep the property, oh well... – Guillaume Racicot Mar 22 '19 at 20:06
  • [Related answer](https://stackoverflow.com/a/40211763/3082296) which uses `Object.getOwnPropertyDescriptor()` to demonstrate this. – adiga Mar 22 '19 at 20:11
  • @GuillaumeRacicot, I'm not sure how you're using this, but you might be able to get the behavior you want by creating a new object with `let newObj = Object.create(obj)` and then setting the `data` property on the new object. It will inherit the getter/setter from the parent. – Mark Mar 22 '19 at 20:17
  • @MarkMeyer I want `obj.oldData` to always yield `obj.wrapper.oldData`. I want incremental migration of a feature. – Guillaume Racicot Mar 22 '19 at 20:19
-1

Consider the following:

let ex = {
  o: 1
}

let ex2 = {
  o: 1
}

console.log(ex === ex2);

Identical objects to not equate.

SpeedOfRound
  • 1,210
  • 11
  • 26