@@ -560,31 +560,51 @@ console.log(newName); // ['Ryan', 'McDermott'];
|
560 | 560 | **[⬆ back to top](#table-of-contents)**
|
561 | 561 |
|
562 | 562 | ### Avoid Side Effects (part 2)
|
563 |
| -Side effects could also occur from inside a function. In JavaScript, primitives are |
564 |
| -passed by value and objects are passed by reference. In the later case, we should be |
565 |
| -careful not to change any of these argument's properties. |
566 |
| - |
567 |
| -A possible solution would be to always clone the variable, edit it and return the |
568 |
| -clone. There would be cases where you actually want to modify the input object |
569 |
| -and this should not be taken as a silver bullet. Furthermore, cloning big objects can |
570 |
| -be very expensive in terms of performance. |
| 563 | +In JavaScript, primitives are passed by value and objects/arrays are passed by |
| 564 | +reference. In the case of objects and arrays, if our function makes a change |
| 565 | +in a shopping cart array, for example, by adding an item to purchase, |
| 566 | +then any other function that uses that `cart` array will be affected by this |
| 567 | +addition. That may be great, however it can be bad too. Let's imagine a bad |
| 568 | +situation: |
| 569 | + |
| 570 | +The user clicks the "Purchase", button which calls a `purchase` function that |
| 571 | +spawns a network request and sends the `cart` array to the server. Because |
| 572 | +of a bad network connection, the `purchase` function has to keep retrying the |
| 573 | +request. Now, what if in the meantime the user accidentally clicks "Add to Cart" |
| 574 | +button on an item they don't actually want before the network request begins? |
| 575 | +If that happens and the network request begins, then that purchase function |
| 576 | +will send the accidentally added item because it has a reference to a shopping |
| 577 | +cart array that the `addItemToCart` function modified by adding an unwanted |
| 578 | +item. |
| 579 | + |
| 580 | +A great solution would be for the `addItemToCart` to always clone the `cart`, |
| 581 | +edit it, and return the clone. This ensures that no other functions that are |
| 582 | +holding onto a reference of the shopping cart will be affected by any changes. |
| 583 | + |
| 584 | +Two caveats to mention to this approach: |
| 585 | +1. There might be cases where you actually want to modify the input object, |
| 586 | +but when you adopt this programming practice you will find that those case |
| 587 | +are pretty rare. Most things can be refactored to have no side effects! |
| 588 | +2. Cloning big objects can be very expensive in terms of performance. Luckily, |
| 589 | +this isn't a big issue in practice because there are |
| 590 | +[https://facebook..io/immutable-js/](great libraries) that allow |
| 591 | +this kind of programming approach to be fast and not as memory intensive as |
| 592 | +it would be for you to manually clone objects and arrays. |
571 | 593 |
|
572 | 594 | **Bad:**
|
573 | 595 | ```javascript
|
574 | 596 | const addItemToCart = (cart, item) => {
|
575 | 597 | cart.push({ item, date: Date.now() });
|
576 |
| - |
577 |
| -return cart; |
578 | 598 | };
|
579 | 599 | ```
|
580 | 600 |
|
581 | 601 | **Good:**
|
582 | 602 | ```javascript
|
583 | 603 | const addItemToCart = (cart, item) => {
|
584 | 604 | const c = Object.assign({}, cart);
|
585 |
| -
|
| 605 | + |
586 | 606 | c.push({ item, date: Date.now() });
|
587 |
| -
|
| 607 | + |
588 | 608 | return c;
|
589 | 609 | };
|
590 | 610 | ```
|
|
0 commit comments