最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - When is it necessary to use the Object.assign() method to copy an instance of an object? - Stack Overflow

programmeradmin2浏览0评论

The following is an example scenario I made up for my own practice of this problem. If you want to skip straight to the technical details, please see 'Technical Details' below.

I have a personal project I've been working on to learn JavaScript. Basically, the user can design a shoe by picking available options.

The trick is that the left and right shoe must have the same size, among other properties, but things like color, shoe lace texture, etc. can be independent properties per shoe. (I figured this was a decent way for me to practice object manipulation and inheritance).

The user starts off with designing the right shoe; when the "swap" button is clicked to look at the left shoe, the user currently sees a copy of the right shoe (but inverted). Only on the first swapping of shoes is the left shoe generated and made an exact copy of the right shoe. From then onwards, unique options per shoe orientation are preserved. Then, if the user makes specific changes to that left-shoe model, and then switches to the right shoe, the user is supposed to see the exact same right shoe that they had originally designed before they clicked the "swap" button.

So if their right shoe had red laces, they switch to the left shoe view and make the left shoe have a blue lace, then when switching back to the right shoe the user should see red laces!


Technical Details

When I was writing the code for my main project I was running into trouble with the unique options being perserved. For example, if I made the laces green for the left shoe, the right shoe would always have green laces. Troubleshooting down to the problem was easy because the only time the right shoe was losing it's unique options, such as a red lace, was when I would set the lace color for the left shoe.

console.log("THE RIGHT LACE BEFORE: " + rightShoe.laceId);
leftShoe.laceId = 'green';
console.log("THE RIGHT LACE AFTER: " + rightShoe.laceId);

What would log to the console was:

THE RIGHT LACE BEFORE: red

THE RIGHT LACE AFTER: green

Even though I wasn't changing the rightShoe, it was being changed whenever I changed the leftShoe property.

So I went back to where I first define the leftShoe object, which is when the user clicks "swap" for the first time in the life of the script (My amateur thought was why propagate and fill the leftShoe object if the user possibly never customizes the left shoe? Maybe it's being unnecessarily stingy with data, I don't know). From then onward, I never redefined the leftShoe to be a copy of rightShoe or vice versa. I figured that I was getting hung up by the fact that I was probably doing object referencing and, just like with other languages, I was changing the reference and not the value.

Before coming to SO with my troubles, I wanted to make a JSFiddle to recreate the problem. Being that my project is lengthy (around ~1500 lines, including some THREE.js for graphics), I did my best to emulate the process. And so here it is.

Except the JSFiddle worked exactly as I expected it to! The left model preserved it's unique attribute and data set to that attribute. So, I did a little more digging and read about the Object.assign() method. So in my original project code (not the fiddle), I changed this:

leftShoe = rightShoe;

to this:

leftShoe = Object.assign({}, rightShoe);

As excited as I am to have finally gotten this to work, I am equally amused and perplexed because I don't understand why my JSFiddle didn't need the assign() method but my identical project code did. Thank you.

The following is an example scenario I made up for my own practice of this problem. If you want to skip straight to the technical details, please see 'Technical Details' below.

I have a personal project I've been working on to learn JavaScript. Basically, the user can design a shoe by picking available options.

The trick is that the left and right shoe must have the same size, among other properties, but things like color, shoe lace texture, etc. can be independent properties per shoe. (I figured this was a decent way for me to practice object manipulation and inheritance).

The user starts off with designing the right shoe; when the "swap" button is clicked to look at the left shoe, the user currently sees a copy of the right shoe (but inverted). Only on the first swapping of shoes is the left shoe generated and made an exact copy of the right shoe. From then onwards, unique options per shoe orientation are preserved. Then, if the user makes specific changes to that left-shoe model, and then switches to the right shoe, the user is supposed to see the exact same right shoe that they had originally designed before they clicked the "swap" button.

So if their right shoe had red laces, they switch to the left shoe view and make the left shoe have a blue lace, then when switching back to the right shoe the user should see red laces!


Technical Details

When I was writing the code for my main project I was running into trouble with the unique options being perserved. For example, if I made the laces green for the left shoe, the right shoe would always have green laces. Troubleshooting down to the problem was easy because the only time the right shoe was losing it's unique options, such as a red lace, was when I would set the lace color for the left shoe.

console.log("THE RIGHT LACE BEFORE: " + rightShoe.laceId);
leftShoe.laceId = 'green';
console.log("THE RIGHT LACE AFTER: " + rightShoe.laceId);

What would log to the console was:

THE RIGHT LACE BEFORE: red

THE RIGHT LACE AFTER: green

Even though I wasn't changing the rightShoe, it was being changed whenever I changed the leftShoe property.

So I went back to where I first define the leftShoe object, which is when the user clicks "swap" for the first time in the life of the script (My amateur thought was why propagate and fill the leftShoe object if the user possibly never customizes the left shoe? Maybe it's being unnecessarily stingy with data, I don't know). From then onward, I never redefined the leftShoe to be a copy of rightShoe or vice versa. I figured that I was getting hung up by the fact that I was probably doing object referencing and, just like with other languages, I was changing the reference and not the value.

Before coming to SO with my troubles, I wanted to make a JSFiddle to recreate the problem. Being that my project is lengthy (around ~1500 lines, including some THREE.js for graphics), I did my best to emulate the process. And so here it is.

Except the JSFiddle worked exactly as I expected it to! The left model preserved it's unique attribute and data set to that attribute. So, I did a little more digging and read about the Object.assign() method. So in my original project code (not the fiddle), I changed this:

leftShoe = rightShoe;

to this:

leftShoe = Object.assign({}, rightShoe);

As excited as I am to have finally gotten this to work, I am equally amused and perplexed because I don't understand why my JSFiddle didn't need the assign() method but my identical project code did. Thank you.

Share Improve this question edited Apr 19, 2016 at 22:02 8protons asked Apr 19, 2016 at 21:39 8protons8protons 3,9596 gold badges34 silver badges71 bronze badges 14
  • In the first case, both variables reference the same object. In the second case, you're creating a new object ({}) and copy all properties using Object.assign. Mutating one object won't reflect in the other. – Bergi Commented Apr 19, 2016 at 21:54
  • @Bergi Thank you, I think that's making sense to me now. Quite standard with other languages. But what is throwing me off now is my JSFiddle. If you please take a look at my reference assignment on line 35 of the Fiddle I linked, you'll see that the values for the left option are being changed independently of the fact that it's a referenced object. – 8protons Commented Apr 19, 2016 at 21:55
  • 1 You didn't, you wrote two console.logs that ended up with the same value. Doesn't make a difference. Regardless, I just don't see what is behaving unexpected in that fiddle. Maybe put the output you're getting in your question, and point to the line where you expected something else. – Bergi Commented Apr 19, 2016 at 22:06
  • 1 Why wouldn't leftChoice.id be 444 right after you have set it to that value? Of course, rightChoice.id will now give 444 as well, since they still point to the same object. – Bergi Commented Apr 19, 2016 at 22:10
  • 1 It will change it's value when you assign to it. Most probably you have overwritten it (possibly via rightChoice that points to the same object) before logging it. – Bergi Commented Apr 19, 2016 at 22:12
 |  Show 9 more comments

1 Answer 1

Reset to default 19

Object.Assign makes a new COPY of the left shoe, including all enumerable OWN properties. When you use leftshoe = rightshoe, you are making a REFERENCE to the left shoe. A reference points to the same object, not a NEW COPY. Thus changing a property of the reference is actually changing the original, as you noted.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论