The Recycling Trap
Descriptors can be recycled without problems and reused to define same things here and there. However, there is an undesired side effect about recycled descriptors: these works with constant/static values, getters, or setters, but are unable to change behavior in their lifetime.var propertiesDescriptor = { shared: { value: Math.random() } };Above descriptor is just a basic example where
Object.defineProperties({}, propertiesDescriptor)
will pollute the empty object with always the same random value.
var a = Object.defineProperties({}, propertiesDescriptor), b = Object.defineProperties({}, propertiesDescriptor); a.shared === b.shared; // true !
Describe A Descriptor With Descriptors
This sounds like a descriptorception and it's actually exactly that one: a property described as property descriptor, able to be different every time the descriptor is used to define properties.Here how we could enrich the
propertiesDescriptor
object in order to have a runtime
property too.
Object.defineProperty( propertiesDescriptor, 'runtime', { enumerable: true, // a getter is required get: function () { // so that every time the object // is used as properties descriptor // this returned value will be used // as "runtime" descriptor instead return { value: Math.random() }; } } );We can perform the check one mor time now against same code.
var a = Object.defineProperties({}, propertiesDescriptor), b = Object.defineProperties({}, propertiesDescriptor); a.shared === b.shared; // true ! a.runtime !== b.runtime; // true again, hooray!
Non Scalar Only Values: Achievement Unlocked
This is pretty much what we have achieved with latest trick: the possibility to recycle and reuse a descriptor being sure this will hold all static/scalar/constant properties as we wanted, and also create new objects, methods, or features, each time the same descriptor is used to define one or more property.A Basic Counter Example
Let's say we'd like to know how many times the same properties descriptor has been used during a program lifecycle, you know what I mean ? All together:var propertiesDescriptor = { shared: { value: Math.random() } }; Object.defineProperty( propertiesDescriptor, 'runtime', { enumerable: true, get: function () { this.__count__++; return { value: Math.random() }; } } ); Object.defineProperty( propertiesDescriptor, '__count__', { writable: true, value: 0 } ); var a = Object.defineProperties({}, propertiesDescriptor), b = Object.defineProperties({}, propertiesDescriptor); alert([ a.shared, // 0.1234 b.shared, // 0.1234 a.runtime, // 0.5678 b.runtime // 0.8901 ].join('\n')); alert(propertiesDescriptor.__count__); // 2
Lazy Value But Not Lazy Property
The last example is about creating a descriptor with a specific property that will create a new value once the descriptor has been used with a generic object.This time is about creating a lazy property value only when accessed through the extended object and not through the property name descriptor ... right ?
var propertiesDescriptor = { shared: { value: Math.random() }, lazy: { configurable: true, get: function () { return Object.defineProperty( this, 'lazy', { value: [] } ).lazy; } } }; // OR Object.defineProperty( propertiesDescriptor, 'lazy', { enumerable: true, value: { configurable: true, get: function () { return Object.defineProperty( this, 'lazy', { value: [] } ).lazy; } } } );At this point the object, let's say a generic
constructor.prototype
, will be described as shared accessor so that each instance, together with the prototype
itself, could redefine that property only when accessed.This is in theory better for memory usage and GC operations but hey ... I've said since the beginning these were just tricks, isn't it?
Sim Sala Bim!
Have you compared this performance-wise with not reusing? Probably faster, but may not be or not much.
ReplyDeletenot yet but it's evident that Garbage Collector wil have less work to do and RAM will be slightly more preserved.
ReplyDeleteI expect the function invocation to be almost as fast as new object creation thought ... a test might come pretty soon, good point.