louis-bompart / the-pitfall-of-spread

Home Page:https://louis-bompart.github.io/the-pitfall-of-spread/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Spread+getter=:finnadie:

Abstract

A common pattern to "extends" object and or clone them is to use the spread operator, this can lead to this kind of bizarre behavior when used with getter:

let counter = 0;
const original = {
    get counter() {
        return counter++;
    }
};
const copy = {...original};
console.log('original.counter, expecting 0, but found:', original.counter);
// Okay, if original.counter is 1, if I call copy.counter, it should be 2, right?
console.log('copy.counter, expecting 2, but found:', copy.counter);
original.counter, expecting 0, but found: 1
copy.counter, expecting 2, but found: 0

Problem

While getter looks like function, they are a Property without value and instead with a get implementation. Most read operation will use the [[Get]] internal method which will execute the get and use its return value as value. This means that, when copy an object containing getter properties, those are evaluated, and the result of the evaluation is then assigned in the spread object.

Solution

Instead of copying value, we need to copy property descriptors. Property Descriptor can be considered a "subset" of Property, minus the name ECMAScript comes with various methods to manipulate those:

With the 2nd & 4th methods, we can craft a "spread for properties" like so:

let counter = 0;
const original = {
    get counter() {
        return counter++;
    }
};
const copy = Object.defineProperties({}, Object.getOwnPropertyDescriptors(original));
console.log('original.counter, expecting 0, found:', original.counter);
console.log('copy.counter, expecting 1, found:', copy.counter);
console.log('original.counter, expecting 2, found:', original.counter);
original.counter, expecting 0, found: 0
copy.counter, expecting 1, found: 1
original.counter, expecting 2, found: 2

About

https://louis-bompart.github.io/the-pitfall-of-spread/


Languages

Language:HTML 98.4%Language:Jupyter Notebook 1.6%