Some JS Descriptor Trick
I am back home for 20 minutes after 10 days of vacation in Italy and already bored so which better way than talk about some wizardish trick about JS descriptors? (yes, they were showing again the great wizard of OZ in the United Airline flight from Frankfurt ... thanks for wondering...)
Here how we could enrich the
This time is about creating a lazy property value only when accessed through the extended object and not through the property name descriptor ... right ?
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!
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.Above descriptor is just a basic example where
var propertiesDescriptor = {
shared: {
value: Math.random()
}
};
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. We can perform the check one mor time now against same code.
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()
};
}
}
);
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 ?
At this point the object, let's say a generic
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;
}
}
}
);
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!
Comments
Post a Comment