Did you know you can attach a key to a JavaScript object that is actually a callable?
For example:
const data = await response.json()
Object.defineProperty(data, 'magic', {
get: () => {
return Math.random()
},
})
console.log({magic: data.magic})
will print:
{ magic: 0.6778944803790492 }
And suppose you want it memoized, you can use this:
const data = await response.json()
let magic
Object.defineProperty(data, 'magic', {
get: () => {
return magic ??= Math.random()
},
})
console.log({magic: data.magic})
console.log({magic: data.magic})
console.log({magic: data.magic})
will print:
{ magic: 0.21367035961590308 } { magic: 0.21367035961590308 } { magic: 0.21367035961590308 }
Note that it doesn't allow setting. If you do this:
Object.defineProperty(data, 'magic', {
get: () => {
return Math.random())
},
set: () => {
throw new Error('Nope!')
},
})
data.magic = 42
it will print:
Error: Nope!
One thing that bit me today, and much the reason why I'm writing this, is that I had this:
async function getData() {
const response = await get()
const data = await response.json()
Object.defineProperty(data, 'magic', {
get: () => {
return Math.random()
},
})
return {...data}
}
// Example use:
const {userName, magic} = await getData()
console.log({userName, magic})
// Will print
// { userName: 'peter', magic: undefined }
This does not work because the magic
property is not enumerable. To fix that, make this edit:
Object.defineProperty(data, 'magic', {
get: () => {
return Math.random()
},
+ enumerable: true,
})
Now, the same code as above, when you run console.log({userName, magic})
it will print:
{ userName: 'peter', magic: 0.23560450431932733 }
Comments