1

I'd like to ask a question about what is specified in the documentation:

The CustomEvent interface imposes no type requirements or structure on the detail property. However it’s important to send only primitive data. JavaScript passes all data types by reference except for primitives. If a component includes an object in its detail property, any listener can mutate that object without the component’s knowledge. This is a bad thing! It’s a best practice either to send only primitives, or to copy data to a new object before adding it to the detail property. Copying the data to a new object ensures that you’re sending only the data you want, and that the receiver can’t mutate your data.

How is sending an actual record data in an object different from extracting some data from the record and then again sending it in an object? This sentence baffles me: "Copying the data to a new object ensures that you’re sending only the data you want, and that the receiver can’t mutate your data."

1 Answer 1

2

This is a OOP question. No matter which framework you're using, nor the language, that guideline is always valid.

It means: do not pass the reference of a local object. If you do so, you may experience unexpected behavior because you cannot know when and who will change its property.

I think it may be clearer with an example:

class TestReference {
    list = ['A', 'B', 'C'];
    position = {
        latitude: 40,
        longitude: 14
    };
    
    sendData() {
        const payload = {
            detail: {
                list: this.list,
                position: this.position
            }
        };
        const event = new CustomEvent('myevent', payload);
        return event;
    }
    
    get listSize() {
        return this.list.length;
    }
    
    get latitude() {
        return this.position.latitude;
    }
    
}

var ref = new TestReference();
// the next line prints 3
console.log(ref.listSize);
var event = ref.sendData();
event.detail.list.splice(0, 1);
// the next line prints 2 because the event's payload holds a reference to the local object "list"
console.log(ref.listSize);

// the next line prints 40
console.log(ref.latitude); 
event.detail.position.latitude = 30;
// the next line prints 30 because the event's payload holds a reference to the local object "position"
console.log(ref.latitude); 

Changing the value of those objects in an unkwnown entity (i.e. another component) could lead to a lot of headache in debugging unexpected behavior, like reading different value for list.length even if you never changed it in the proper class. You'll lose consistency if you do so.

Otherwise, if you clone those object, the class behavior will be coherent.
In order to clone an object you can use Spread syntax

sendData() {
    const payload = {
        detail: {
            list: [...this.list], // create a new list with the same values
            position: {...this.position} // create a new object with the same values
        }
    };
    const event = new CustomEvent('myevent', payload);
    return event;
}

Unless you're developing for your own use and be 100% sure no one will ever touch that code, even a future you, please never, never, think something like "why should I bother with such nuisance, everyone will know how it works and how it should work."
There will always be someone who will do the wrong thing with a piece of code, so design it to be robust.
Sorry for the rant.

By the way, you may want to read about SOLID principles and why there are getter and setters. I'm pretty sure there are a lot of questions on Software Engineering subdomain.

1
  • Thanks a lot, Ruben! I will read about SOLID principles and getters and setters.
    – DevelBase2
    Commented Mar 15, 2022 at 8:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .