When you use Object.defineProperty ()

I am wondering when should I use

Object.defineProperty 

to create new object properties. I know that I can install things like

 enumerable: false 

but when do you need it? If you just set a property like

 myObject.myprop = 5; 

all its descriptors are set to true, right? I'm more curious when you guys use this rather detailed call to .defineProperty () and for what reasons.

+58
javascript ecmascript-5
Apr 11 2018-12-12T00:
source share
10 answers

Object.defineProperty is mainly used to set properties with specific property descriptors (for example, read-only (constants), enumerations (so as not to show the property in for (.. in ..) , getters, seters).

 "use strict"; var myObj = {}; // Create object // Set property (+descriptor) Object.defineProperty(myObj, 'myprop', { value: 5, writable: false }); console.log(myObj.myprop);// 5 myObj.myprop = 1; // In strict mode: TypeError: myObj.myprop is read-only 

Example

This method extends the Object prototype with the property. Only getter is defined, and enumeration is set to false .

 Object.defineProperty(Object.prototype, '__CLASS__', { get: function() { return Object.prototype.toString.call(this); }, enumerable: false // = Default }); Object.keys({}); // [] console.log([].__CLASS__); // "[object Array]" 
+38
Apr 11 2018-12-12T00:
source share

Features like "enumerated" are rarely used in my experience. The main use cases are calculated properties:

 var myObj = {}; myObj.width = 20; myObj.height = 20; Object.defineProperty(myObj, 'area', { get: function() { return this.width*this.height; } }); console.log(myObj.area); 
+22
Jan 10 '14 at 13:23
source share

A really useful reason to use Object.defineProperty is that it allows you to scroll the function in the object as a computed property that executes the function instead of returning the body of the function.

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 

Compared to adding a 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;} 

Verify that the property of the enumerated value is set to true to loop through it.

+13
May 6 '16 at 11:37
source share

One simple use case I saw for defineProperty is that libraries provide an error property to the user, which, if it is not available at a certain interval, you will throw yourself away. 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/ddd3d8faabf135dca691d20ce8ab0bc24ccc414e/src/graphql.tsx#L510

+2
Jun 22 '17 at 18:38
source share

For example, that Vue.js tracks changes in the data object :

When you pass a simple JavaScript object to a Vue instance as its data option, Vue looks at all its properties and converts them to getter/setters using Object.defineProperty . This is an ES5 feature only for working with asymmetrical elements, so Vue does not support IE8 or lower.

The receiver / installer is invisible to the user, but internally they allow Vue to track dependencies and notify you of changes when accessing or changing properties.

[...]

Keep in mind that even the ultra-thin and basic version of Vue.js will use something more than just Object.defineProperty , but the basic functionality comes from this:

Vue.js's Reactivity Cycle

Here you can see an article in which the author implements a minimal version of the PoC version of something like Vue.js: https://medium.com/js-dojo/understand-vue-reactivity-implementation-step-by-step-599c3d51cd6c

And here is the conversation (in Spanish), where the speaker builds something similar, explaining the reactivity in Vue.js: https://www.youtube.com/watch?v=axXwWU-L7RM

+2
Aug 13 '19 at 22:20
source share

A good use is when you need to intercept or apply the classic Observer / Observable pattern in an elegant way:

https://www.monterail.com/blog/2016/how-to-build-a-reactive-engine-in-javascript-part-1-observable-objects

+1
Jul 06 '17 at 14:30
source share

Summary:

In Javascript, objects are collections of key-value pairs. Object.defineProperty() is a function that can define a new property of an object and can set the following property attributes:

  • <any> value : the value associated with the key
  • recordable <boolean> : if the record parameter is set to true The property can be updated by assigning it a new value. If set to false , you cannot change the value.
  • enumerable <boolean> : if enumerable is set to true The property can be accessed through the for..in . In addition, the only enumerable property keys returned with Object.keys()
  • configurable <boolean> : If configurable is set to false , you cannot change the change of property attributes (value / writable / enumerable / configurable), either, since you cannot change the value, you cannot delete it using the delete operator.

Example:

 let obj = {}; Object.defineProperty(obj, 'prop1', { value: 1, writable: false, enumerable: false, configurable: false }); // create a new property (key=prop1, value=1) Object.defineProperty(obj, 'prop2', { value: 2, writable: true, enumerable: true, configurable: true }); // create a new property (key=prop2, value=2) console.log(obj.prop1, obj.prop2); // both props exists for(const props in obj) { console.log(props); // only logs prop2 because writable is true in prop2 and false in prop1 } obj.prop1 = 100; obj.prop2 = 100; console.log(obj.prop1, obj.prop2); // only prop2 is changed because prop2 is writable, prop1 is not delete obj.prop1; delete obj.prop2; console.log(obj.prop1, obj.prop2); // only prop2 is deleted because prop2 is configurable and prop1 is not 

+1
04 Sep '18 at 18:26
source share

Object.defineProperty prevents accidental assignment of values ​​to a certain key in its prototype chain . With this method, you assign only to this specific level of the object (but not the key in the prototype chain).

For example: There is such an object as {key1: value1, key2: value2} , and you do not know exactly its prototype chain or miss it by mistake, and somewhere in the prototype chain there is some kind of property 'color' then-

using dot (.) assignment-

this operation will assign a value to the 'color' key in the prototype chain (if the key exists somewhere), and you will find the object without changes as. obj.color = 'blue'; // the object remains the same as {key1: value1, key2: value2}

using the Object.defineProperty method -

 Object.defineProperty(obj, 'color', { value: 'blue' }); 

// now the object looks like {key1: value1, key2: value2, color: 'blue'} . he adds the property to the same level. You can then iterate safely using the Object.hasOwnProperty() method.

+1
Nov 10 '18 at 12:11
source share

A very useful case is to follow the changes of something and work on them. This is easy because you can call callback functions whenever a value is set. Here is a basic example.

You have a Player object that may or may not play. You want something to happen just when he starts playing, and just when he stops playing.

 function Player(){} Object.defineProperty(Player.prototype, 'is_playing', { get(){ return this.stored_is_playing; // note: this.is_playing would result in an endless loop }, set(newVal){ this.stored_is_playing = newVal; if (newVal === true) { showPauseButton(); } else { showPlayButton(); } } }); const cdplayer = new Player(); cdplayer.is_playing = true; // showPauseButton fires 

This answer is linked to a couple of other answers, which are good starting points for more information, but there is no need to follow external links to read about libraries or programming paradigms.

0
Sep 28 '19 at 19:21
source share

@ Gerard Simpson

If 'area' must be enumerable, it can also be written without Object.defineProperty.

 var myObj = { get area() { return this.width * this.height } }; myObj.width = 20; myObj.height = 20; for (var key in myObj) { if (myObj.hasOwnProperty(key)) { console.log(key + " -> " + myObj[key]); } } //area -> 400, width -> 20, height -> 20 
-one
Dec 11 '16 at 11:22
source share



All Articles