I\'m wondering when I should use
Object.defineProperty
to create new properties for an object. I\'m aware that I\'m able to set things lik
One neat use case I have seen for defineProperty
is for libraries to provide an error property to the user which, if it's not accessed within a certain interval you would throw yourself. For example:
let logErrorTimeoutId = setTimeout(() => {
if (error) {
console.error('Unhandled (in <your library>)', error.stack || error);
}
}, 10);
Object.defineProperty(data, 'error', {
configurable: true,
enumerable: true,
get: () => {
clearTimeout(logErrorTimeoutId);
return error;
},
});
Source for this code: https://github.com/apollographql/react-apollo/blob/ffffd3d8faabf135dca691d20ce8ab0bc24ccc414e/src/graphql.tsx#L510
A really good reason for using Object.defineProperty is that it lets you loop through a function in an object as a computed property, which executes the function instead of returning the function's body.
For example:
var myObj = {};
myObj.width = 20;
myObj.height = 20;
Object.defineProperty(myObj, 'area', {
get: function() {
return this.width*this.height;
},
enumerable: true
});
for (var key in myObj) {
if (myObj.hasOwnProperty(key)) {
console.log(key + " -> " + myObj[key]);
}
}
//width -> 20, height -> 20, area -> 400
Versus adding the function as a property to an object literal:
var myObj = {};
myObj.width = 20;
myObj.height = 20;
myObj.area = function() {
return this.width*this.height;
};
for (var key in myObj) {
if (myObj.hasOwnProperty(key)) {
console.log(key + " -> " + myObj[key]);
}
}
// width -> 20, height -> 20, area -> function() { return this.width*this.height;}
Make sure you set the enumerable property to true in order to loop through it.
A good use is when you need to do some interception or apply a classical Observer/Observable pattern in a elegant way:
https://www.monterail.com/blog/2016/how-to-build-a-reactive-engine-in-javascript-part-1-observable-objects
Features like 'enumerable' are rarely used in my experience. The major use case is computed properties:
var myObj = {};
myObj.width = 20;
myObj.height = 20;
Object.defineProperty(myObj, 'area', {
get: function() {
return this.width*this.height;
}
});
console.log(myObj.area);