My understanding of defineProperty was wrong. I thought this would allow you to set the getter / setter to an existing property. Then common sense will adhere to the fact that the setter either simply returns a new value, or if the user needs to set the actual property inside the setter, at least assigning this property will not lead to a restart of the setter.
However, this is not the functionality that was created using defineProperty. Rather, it is designed to create interfaces. You create an accessor property, which in itself does not store any data, but which can display some other data from the data structure, possibly hidden from the client through the interface. This is a powerful feature, albeit a bit unpleasant, if you just decided to quickly add a check on one of your properties.
MDN is not very clear on this, and therefore it can be confusing, especially since the “other” use of defineProperty is to set attributes on a property that matters. A getter / setter are not attributes of this property, but are separate from it. Note that your setter will not receive the name of the property being accessed. Therefore, if you want to create a common code, you will need to wrap it with an anonymous function in order to pass the name. If you are doing generic code, you probably assign properties in a loop anyway, so you will have to use anonymous to deal with the “closing effect” anyway.
What I wanted to use for this is to make a public interface for a private object. The problem is that if the client assigns something to a property on the interface, it will disconnect it from the private partner, and closed and open code will no longer act on the same value. It turns out that in this case, the defineProperty method works because I already have a private (reference) object, and I want to create accessors on another object that allows me to access this data without having access to the private object.
Code example: If you need a common set / receiver (for example, assigned in a loop and actual code existing elsewhere, so that each property on all your objects does not need a full copy of the function), you will need:
Create secondary storage for the actual property value.
wrap your call to defineProperty with an anonymous function to work with closure and create a built-in getter / setter that will call your actual getter / setter with the property name.
This will work as expected:
var properties = { q:1, b:2, c:3 } var backends = [ {}, {} ] var iFaces = [ {}, {} ] for( var key in properties ) { for( var l = iFaces.length - 1; l >= 0; --l ) { ;(function( iFace, backend, name ) { Object.defineProperty ( iFace , name , { enumerable : true , configurable: false , set: function setter( value ){ _setter( backend, name, value ) } , get: function getter( ){ return _getter( backend, name ) } } ) })( iFaces[ l ], backends[ l ], key ) iFaces[ l ][ key ] = properties[ key ] } } function _setter( backend, name, value ) { // do some validation //... backend[ name ] = value } function _getter( backend, name ) { // keep access logs for example //... return backend[ name ] } iFaces[ 1 ].b = "Bananas, it works!" console.log( backends ); console.log( iFaces[ 1 ].b ); // ouput: // [ { q: 1, b: 2, c: 3 }, // { q: 1, b: 'Bananas, it works!', c: 3 } ] // Bananas, it works!