Most elegant solution required please. We all deal with objects that can be constructed incrementally throughout their lifecycle. Passing object references is the most useful way of dealing with objects, as mutations affect the original rather than just a copy.
For example:
const bigObject = fetchBigObjectFromStorage()
let myMem = bigObject.member || {}
If member
exists within bigObject
, myMem
gets a reference to it. If not, it just receives a reference to a new empty object. So this has unpredictable results:
myMem.value = 30
No errors. myMem.value
is now 30. But did the value end up where we actually wanted it?
console.log(bigObject.member.value)
This either displays 30 or gives a TypeError
because bigObject.member
is undefined, depending on whether or not bigObject.member
existed already.
To avoid errors, we could put the new value back into bigObject
, and get it put back there every time, we'd need to explicitly assign it thus:
bigObject.member = myMem
which is messy.
So we could pre-empt the possibility that bigObject.member
isn't there, test for it, and insert it before we start trying to pass a reference to it around, even initialising required members with null values. So we have this code:
const bigObject = fetchBigObjectFromStorage()
if (!bigObject.hasOwnProperty("member")) bigObject.member = {value: null}
let myMem = bigObject.member
myMem.value = 30
console.log(bigObject.member.value)
... and we'll get no errors, 30 displayed, and reliable behaviour every time (well, almost... a couple more tests in the if
might make it watertight). But it's as ugly as sin and too much code for something so trivial. We could refactor bits of it like that if
statement into a little function, make it a generic member initialiser, and a few other approaches besides. I'm sure most of us have tried lots of techniques over the years. But what's the most elegant, most favoured solution from the assembled learned throng? Any clever little tricks?