Well, just in case you read RSS and you missed my tweet ... everything you need to know in github repository.
Have fun with Harmony Collections
behind the design
My JavaScript book is out!
Don't miss the opportunity to upgrade your beginner or average dev skills.
Wednesday, January 18, 2012
Monday, January 16, 2012
On EventEmitter In node.js
Today I had a whole node.js session and I have spent a bit of time looking at current EventEmitter implementation.
I have twitted already that it sucks as it is, and while it's really trivial to implement the same for any browser, I believe many mistakes have been made about the API. Here the list:
I have personally created wru which runs in all browsers and many server side JS environments but what I would like to avoid is to write twice any sort of test because of weirdly implemented APIs.
If it's about shortcutting, as example, on() and off() are more than welcome but why on earth the long version should be addListener rather than addEventListener?
Why events passed as objects since ever in client JS should be passed as string with optional extra data as second argument?
Where are defaults control over events fired across more listeners?
Why on earth handleEvent is not supported and a listener can be only a function which most likely will require a bind to something else?
Why is it possible to erase all listeners without even knowing "who set them where" but it's not possible to retrieve all of them so that at least we could act accordingly with the event name following some rule rather than "just remove them all" ?
I hope somebody will agree with me, considering flakey points I have already described and changing or improving ASAP this EventEmitter API ... it would be sooooooo coooool to be aligned in both worlds for at least the most used pattern/procedure ever in JS world, don't you say? Thanks for your attention.
I have twitted already that it sucks as it is, and while it's really trivial to implement the same for any browser, I believe many mistakes have been made about the API. Here the list:
- on() is a shortcut for addListener but there is no off() as removeListener's shortcut (inconsistent)
- add/removeListener is not DOM friendly, we cannot reuse an EventEmitter in the browser without double checking if those methods exist
- removeAllListeners() accepts no arguments and cleans up the whole emitter but there is no way to retrieve all listeners via listeners() passing no arguments (again, inconsistent)
- there's no possibility to use handleEvent property, as already defined in the EventListener, once again objects are not reusable between client and server
- no duplicated checks for both addListener and removeListener, this is totally inconsistent against DOM EventTarget plus I found it kinda hilarious since there is also a max number of listeners allowed defined via setMaxListeners method ... if we add same listener twice, it's fired twice ... a non-sense for those coming from the web. We also need to removeListener twice or more 'cause we have no idea if same listeners has been added by mistake twice so ... it's just screwed up, removing a specific listener may be not enough and there is no easy way to check if the listener has been removed or not
- there is no interface to define events plus the single argument is not a DOM Event like, not even an object with data property and at least a type that points to the event name ... once again, not possible to reuse anything on DOM world
Why All Of This Is Bad
node.js is bringing a lot of non JavaScripters and non browser friendly JS developers into its community and this is the good part. What is absolutely bad is that if node.js won't be minimally aligned with the rest of the code in the browsers out there our life as "one language everywhere" will become harder than ever.I have personally created wru which runs in all browsers and many server side JS environments but what I would like to avoid is to write twice any sort of test because of weirdly implemented APIs.
If it's about shortcutting, as example, on() and off() are more than welcome but why on earth the long version should be addListener rather than addEventListener?
Why events passed as objects since ever in client JS should be passed as string with optional extra data as second argument?
Where are defaults control over events fired across more listeners?
Why on earth handleEvent is not supported and a listener can be only a function which most likely will require a bind to something else?
Why is it possible to erase all listeners without even knowing "who set them where" but it's not possible to retrieve all of them so that at least we could act accordingly with the event name following some rule rather than "just remove them all" ?
I hope somebody will agree with me, considering flakey points I have already described and changing or improving ASAP this EventEmitter API ... it would be sooooooo coooool to be aligned in both worlds for at least the most used pattern/procedure ever in JS world, don't you say? Thanks for your attention.
Sunday, January 15, 2012
Y U NO use libraries and add stuff
This is an early introduction to a project I have been thinking about for a while.
The project is already usable in github but the documentation is lacking all over the place so please be patient and I'll add everything necessary to understand and use yuno.
If we are using a generic JS loader, the aim is to simply download files and eventually wait for one or more dependency in order to be able to use everything we need.
The require logic introduced via node.js does not scale in the browser due synchronous nature of the method itself plus the sandbox not that easy to emulate in a browser environment.
The AMD concept is kinda OKish but once we load after dependencies, there is no way to implement a new one within the callback unless we are not exporting.
I find AMD approach surely the most convenient but still not the best one:
Specially the last point means that AMD does not scale properly with already combined code because AMD relies in the module/folder structure itself ... so, cannot we do anything better than what we have so far?
Directly out of a well known meme, yuno logic is quite straightforward:
Let's imagine that extraStuff contains similar code:
Both plugin and extraStuff needs jQuery to be executed ... will jQuery be loaded twice? Nope, it's simply part of a queue of modules that needs to be resolved.
As soon as it's loaded/added once, every module that depends on jQuery will be notified so that if the list of dependencies is fully loaded, the callback passed to and will be executed.
The yuno.add method reflects Object.defineProperty which means for ES5 compatible browsers getters, setters, and values, are all accepted and flagged as not enumerable, not writable, and not configurable by default.
Of course we can re-define this behavior but most likely this is what we need/want as default in any case ... isn't it?
For those browsers not there yet, the Object.defineProperty method is partially shimmed where __defineGetter/Setter__ or simply the value property will be used instead.
Bear in mind this shim may change accordingly with real needs but so far all mobile browsers should work as expected plus all Desktop browsers except IE less than 9 ... not so common targets for modern web sites.
Last, but not least, yuno logic does not necessarily need the add call so feel free to simply define your global object or your namespace the way you want.
However, as I have said before, the add method is a simple call able to make things more robust, to speedup and ensure notifications, and to use a standard, recognizable pattern, to define our own objects/functions being sure nobody did before thanks to defaults descriptor behavior which is not writable and not configurable indeed.
Last, but not least, the reason I am writing this is because I am personally not that happy with any solution we have out there so if you are willing to contribute, please just leave a comment, thanks.
The project is already usable in github but the documentation is lacking all over the place so please be patient and I'll add everything necessary to understand and use yuno.
Zero Stress Namespace And Dependencies Resolver
Let's face the reality: today there is still no standard way to include dependencies in a script.If we are using a generic JS loader, the aim is to simply download files and eventually wait for one or more dependency in order to be able to use everything we need.
The require logic introduced via node.js does not scale in the browser due synchronous nature of the method itself plus the sandbox not that easy to emulate in a browser environment.
The AMD concept is kinda OKish but once we load after dependencies, there is no way to implement a new one within the callback unless we are not exporting.
I find AMD approach surely the most convenient but still not the best one:
- we cannot implement a provide like procedure, whenever this could be handy or not
- it's not clear within the module code itself, what we are exporting exactly
Specially the last point means that AMD does not scale properly with already combined code because AMD relies in the module/folder structure itself ... so, cannot we do anything better than what we have so far?
The yuno Concept
Directly out of a well known meme, yuno logic is quite straightforward:
- automagically resolved path, you point once to yuno.js file in your page and you are ready to go
- compatible with already combined files (smart builder coming soon)
- yuno.use() semantic method to define dependencies, if necessary
- yuno.use().and() resolved callback to receive modules AMD style once everything has been loaded
- yuno.add() standard ES5 way to define new namespaces, objects, properties, or constructors ( so no extra note in the documentation is needed )
- cross referenced dependencies automagically resolved: if two different scripts needs same library, this will be loaded once for both
- external url compatible, because you may want to include a file from some known CDN rather than put all scripts in your own host ( speed up common libraries download across different libraries that depend on same core, e.g/ jQuery )
- modules, namespaces, or global objects, cannot be reassigned twice, which means if we are adding twice same thing we are doing it wrong, but if we are not aware of other script that added same thing before we have a notification
- something else I may decide to add after this post
// define a jQuery plugin
yuno.use(
"jQuery",
"extraStuff"
).and(function (jQuery, extraStuff) {
yuno.add(jQuery.fn, "myPlugin", {value:function () {
// your amazing code here
}});
// we may opt for just this line
jQuery.fn.myPlugin = function () {};
// in order to export our plugin
// however, the purpose of yuno is to have
// a common recognizable way to understand
// what the module is about
// plus the "add" method is safer
});
Let's imagine that extraStuff contains similar code:
// define extraStuff
yuno.use(
"jQuery"
).and(function (jQuery) {
yuno.add(jQuery.fn, "extraStuff", {value:function () {
// your amazing code here
}});
});
Both plugin and extraStuff needs jQuery to be executed ... will jQuery be loaded twice? Nope, it's simply part of a queue of modules that needs to be resolved.
As soon as it's loaded/added once, every module that depends on jQuery will be notified so that if the list of dependencies is fully loaded, the callback passed to and will be executed.
Y U NO Add
Modules are only one part of the proposal since we may define a script where no external dependency is needed.
// note: no external dependency, just add
yuno.add(this, "MyFreakingCoolConstructor", {value:
function MyFreakingCoolConstructor() {
// freaking cool stuff here
}
});
// this points to the global object so that ...
MyFreakingCoolConstructor.prototype.doStuff = function () {
// freaking cool method
};
The yuno.add method reflects Object.defineProperty which means for ES5 compatible browsers getters, setters, and values, are all accepted and flagged as not enumerable, not writable, and not configurable by default.
Of course we can re-define this behavior but most likely this is what we need/want as default in any case ... isn't it?
For those browsers not there yet, the Object.defineProperty method is partially shimmed where __defineGetter/Setter__ or simply the value property will be used instead.
Bear in mind this shim may change accordingly with real needs but so far all mobile browsers should work as expected plus all Desktop browsers except IE less than 9 ... not so common targets for modern web sites.
Last, but not least, yuno logic does not necessarily need the add call so feel free to simply define your global object or your namespace the way you want.
However, as I have said before, the add method is a simple call able to make things more robust, to speedup and ensure notifications, and to use a standard, recognizable pattern, to define our own objects/functions being sure nobody did before thanks to defaults descriptor behavior which is not writable and not configurable indeed.
To DOs
This is just an initial idea of what the yuno object is able to do but few things are in my mind. On top of the list we have the possibility to shortener CDN calls via prefixes such "cdn:jQuery", as example, in order to use most common CDNs to load widely shared libraries.Last, but not least, the reason I am writing this is because I am personally not that happy with any solution we have out there so if you are willing to contribute, please just leave a comment, thanks.
Tuesday, January 10, 2012
Introducing ObjectHandler
since the discussion about a better Function#bind will probably never end, and since a must have dependency would be the ES6 WeakMap which is in any existent shim leak prone due lack of control via ES5+, I have proposed another way to solve the problem.
Above object is an Abstract implementation. In JavaScript we can borrow methods so whatever "class" would like to implement above behavior should extend the object or borrow those two methods and specify an events property.
Got it? Events property is simply an object shared through the prototype with properties name that are exactly the equivalent of DOM events name ... easy!
ObjectHandler IDL Like
/**
* interface ObjectHandler implements EventListener {
* void handleEvent(in Event evt);
* void remitEvent(in Event evt);
* attribute Object events;
* };
*
* @link http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventListener
*/
var ObjectHandler = {
handleEvent: function handleEvent(e) {
var
events = this.events,
type = e.type
;
if (events.hasOwnProperty(type)) {
events[type].call(this, e);
}
},
// it could be called removeEvent too, as you wish
remitEvent: function cancelEvent(e) {
e.currentTarget.removeEventListener(
e.type, this, e.eventPhase === e.CAPTURING_PHASE
);
}
};
Above object is an Abstract implementation. In JavaScript we can borrow methods so whatever "class" would like to implement above behavior should extend the object or borrow those two methods and specify an events property.
Examples
Let's say we have a UI Class which aim is to react to certain events ... let's call it button:
function UIButton(parentNode) {
// add the node
this.el = parentNode.appendChild(
parentNode.ownerDocument.createElement("button")
);
// add quickly events to the node
for (var key in this.events) {
// add the listener ...
// NOTE: nothing to bind, no duplicated entries either
this.el.addEventListener(key, this, false);
}
}
// extends the class
Object.defineProperties(
UIButton.prototype,
{
// implements ObjectHandler
handleEvent: {value: ObjectHandler.handleEvent},
remitEvent: {value: ObjectHandler.remitEvent},
events: {value: {
// only once thanks to remitEvent
click: function (evt) {
alert("only once");
this.remitEvent(evt);
},
// some decoration on actions
mousedown: function (evt) {
this.el.style.border = "1px solid black";
},
mouseup: function (evt) {
this.el.style.border = null;
},
// recicle mouseup behavior
mouseout: function (evt) {
this.events.mouseup.call(this, evt);
}
}}
}
);
// example on window load
this.onload = function () {
new UIButton(document.body);
};
Got it? Events property is simply an object shared through the prototype with properties name that are exactly the equivalent of DOM events name ... easy!
Pros
- memory safe, nothing to bind, trap as bound, and stuff like this ... all instances will share same logic and bind is not even needed, aka: problem solved
- events are defined in a single place, easy to find, maintain, extend
- events are recycled, as it was as example for mouseout, though the instance
- most UI frameworks need the instance rather than the DOM node, to behave accordingly
- ObjectHandler can be used same way for "ObjectTarget", those listeners/able JS implementations, in order to uniform an event driven approach
- no risk to bind twice, no risk to remove the wrong callback, bound or not, it's the instance that makes the deal, not inline functions so it's less error prone
- performances in therms of both memory footprint and operation per each instance ... once again, no need to bind all methods to the instance itself ... what is in events is basically bound automatically through a single entry point, defined in ObjectHandler, for every single use case
Cons
... no idea, I cannot find any and I just like this solution over the Function#bind improvements since it's both cross platform, whenever addEventListener is present, but it can be recycled for any other no DOM use case as long as the event will have a currentTarget property that points to the current instance ( I will write an example/proposal soon ... OK? )As Summary
The main problem with proposal is adoptions and I would like to know UI Framework users feedbacks. Ideally this way to handle events could become a de facto standard dropping the redundant and massive usage of Function#bind for cases where the focus should be for the instance and not for the callback.Wednesday, January 04, 2012
Improving Function.prototype.bind
There are a couple of things I have never liked that much about Function#bind and this post is about proposing a pattern hopefully better than common one.
The parentheses version apparently wins but, specially when no assignment is needed, I believe these are even less ambiguous:
Of course if there is an operator that function will be executed, why on earth anyone would do that otherwise?
Anyway, the problem with all of these human friendly syntax pattern recognition strategies, is that the context of the function, or the whole code behavior, could be polluted/changed via bind or call or apply so we need in any case to scroll 'till the end to better understand what is going on inside the function and what is returned, exactly.
The summary is that bind, used inline, is more like a yoda condition rather than a developer friendly helper so the first point is that bind, as it is, forces the developer to always check the end of the function to know if this has been executed inline or it has been bound to a different context, as well as yoda conditions forces the developer to read "upside down" a statement.
Last, but not least, of course if it's just about bind, parentheses are not helping at all ... still scroll 'till the end
Also if that was "the good part", I mean just putting parentheses around, there is some conflict with the fact that functions should not be that long ... I mean, how can we mistake whatever happened in 10 lines?
The truly good part could be done by developers, specially those that work in a team.
The first good rule is to write a bloody single line comment at the very first line, this would just solve everything:
Got it? Nobody would ever complain about these little helps ... isn't it? But since we are all lazy devs, the second helper is function declaration rather than function expression.
With a single line to read I believe the problem is solved ... isn't it? Still ways to improve.
In my humble opinion, was a freaking design mistake indeed to create a new bound object per each bind call since I believe nobody in this world ever used this "feature".
If the function is the same it means it has same context, inner and outer scope of the other function bound to the same object.
If we bind twice the same object we are doing it wrong 'cause most likely we never meant/need two different bound callbacks/objects for that task ... isn't it?
Above example won't work as expected ... of course it won't work as expected ... developers expect the same function/object, instead they have a new one.
This approach forces developers to store temporarily the bloody bound function to some private, global, variable or property.
Remember how lazy we are so that parentheses became one of the good parts of JavaScript since a line of comment was too boring? Now look again at latest example and think how many times you have done something similar ...
I came up with this proposal in order to solve at least latest problems described before: a lazy boundTo method
How above snippet is supposed to be used? Here a basic example:
The semantic is straight forward and rather than a yoda condition we have a clear operation that means: return the function created to bind this object as context.
Last, but not least, even if the function was not bound, everything should work as expected, as long as the removeListener generic method has been implemented properly ( checking if the callback/object was attached already )
Memory speaking, the very first time we use this strategy we create two extra arrays able to speed up operations through indexed function and and bound version per each object. This is inevitable in any case and it's almost exactly the same we do when we address once the bound function.
Once the object has been Garbage Collected, related private arrays will have a reference count equal to zero so the memory should clean up automatically without problems and including all functions bound to that object.
As explained in the example, it is possible in any case to release explicitly bound functions so we can feel like the memory usage is under control.
It does not really make sense to over complicate such basic, most needed, scenario but if you think this is the biggest impediment, then the name should simply be asContextOf so that no ambiguity would be shared with bind native signature.
Enjoy simplicity over semantic, this is yet another KISS and YAGNI proposal from this blog.
At The End Of The Function
A common argument about parentheses around inline invoked functions is that developers can easily recognize them.
// considered ambiguous
var someThing = function () {
return {};
}();
// considered not ambiguous
var someThing = (function () { // note the parenthesis
return {};
}()); // note the parenthesis
// exact same behavior of latest one
// but considered slightly ambiguous
var someThing = (function () { // note the parenthesis
return {};
})(); // note the parenthesis
The parentheses version apparently wins but, specially when no assignment is needed, I believe these are even less ambiguous:
-function(){
alert("OK");
}();
+function(){
alert("OK");
}();
!function(){
alert("OK");
}();
Of course if there is an operator that function will be executed, why on earth anyone would do that otherwise?
Anyway, the problem with all of these human friendly syntax pattern recognition strategies, is that the context of the function, or the whole code behavior, could be polluted/changed via bind or call or apply so we need in any case to scroll 'till the end to better understand what is going on inside the function and what is returned, exactly.
// ES3 example
var something = (function(){
// this could be global object or something else
return this.doSomeStuff();
}.bind(unexpectedObject)); // or call for other cases
// ES5
var something = (function(){"use strict";
// if there is a this reference
// we need to reach the end to understand
// what is it
return this.doSomeStuff();
}.bind(unexpectedObject));
The summary is that bind, used inline, is more like a yoda condition rather than a developer friendly helper so the first point is that bind, as it is, forces the developer to always check the end of the function to know if this has been executed inline or it has been bound to a different context, as well as yoda conditions forces the developer to read "upside down" a statement.
Last, but not least, of course if it's just about bind, parentheses are not helping at all ... still scroll 'till the end
// perfectly valid, not even executed
// but still important to know
// what will be the context for future calls
var something = function(){
return this.doSomeStuff();
}.bind(unexpectedObject);
Team Speaking
Ok, agreed, a function bigger than 10 lines is not that good and should be split and blah blah blah ... point is that sometimes function have to be big since these provide us a way to create private variables and methods ... ok?Also if that was "the good part", I mean just putting parentheses around, there is some conflict with the fact that functions should not be that long ... I mean, how can we mistake whatever happened in 10 lines?
The truly good part could be done by developers, specially those that work in a team.
The first good rule is to write a bloody single line comment at the very first line, this would just solve everything:
var something = function () {
//! executed inline, returns object
... the rest of the code ...
}();
var somethingElse = function () {
//! bound to variable obj
... the rest of the code ...
}.bind(obj);
var somethingCrazy = function () {
//! bound to obj + executed inline
.. the rest of the code ...
}.bind(obj)();
-function(){
// bound to obj
}.bind(obj)();
Got it? Nobody would ever complain about these little helps ... isn't it? But since we are all lazy devs, the second helper is function declaration rather than function expression.
function impossibruToConfuse(){}
var something = impossibruToConfuse.bind(obj);
var something = impossibruToConfuse();
var something = impossibruToConfuse.call(obj);
With a single line to read I believe the problem is solved ... isn't it? Still ways to improve.
Unable To Retrieve Same Bound Function
The second most annoying thing ever, something that leads inevitably to uncomfortable patterns, is the inability to retrieve an already bound function through the same object.In my humble opinion, was a freaking design mistake indeed to create a new bound object per each bind call since I believe nobody in this world ever used this "feature".
function task(){}
// Y U NO THE SAME !!!
task.bind(window) === task.bind(window);
// false ....
If the function is the same it means it has same context, inner and outer scope of the other function bound to the same object.
If we bind twice the same object we are doing it wrong 'cause most likely we never meant/need two different bound callbacks/objects for that task ... isn't it?
An Error Prone Logic
The most basic fail of this logic is about listeners, both DOM listeners or self implemented listeners, extremely common in an always more asynchronous driven language as JavaScript is.
generic.addEventListener("stuff", stuff.bind(obj), false);
// how many times have you seen this later on?
generic.removeEventListener("stuff", stuff.bind(obj), false);
Above example won't work as expected ... of course it won't work as expected ... developers expect the same function/object, instead they have a new one.
This approach forces developers to store temporarily the bloody bound function to some private, global, variable or property.
obj._boundStuff = stuff.bind(obj);
generic.addEventListener("stuff", obj._boundStuff, false);
// ... later on ...
if (obj._boundStuff) {
generic.removeEventListener("stuff", obj._boundStuff, false);
}
Remember how lazy we are so that parentheses became one of the good parts of JavaScript since a line of comment was too boring? Now look again at latest example and think how many times you have done something similar ...
A Clever Object.prototype.boundTo
With ES5 we are so lucky to be able to pollute global constructors without influencing for/in and as long as our implementation is not obtrusive and, most important, makes sense.I came up with this proposal in order to solve at least latest problems described before: a lazy boundTo method
!function (Object) {
// (C) WebReflection - Mit Style License
var // private scope shortcuts
BOUND_TO = "boundTo", // or maybe "asContextOf" ?
defineProperty = Object.defineProperty,
bind = defineProperty.bind || function (self) {
// simple partial shim for "not there yet" ES5 browsers
var callback = this;
return function bound() {
return callback.apply(self, arguments);
};
}
;
defineProperty(
Object.prototype,
BOUND_TO, {
value: function (callback, remove) {
// only the very first time
// two private stacks are created
// and related to the current object
var
cbStack = [],
boundStack = [],
self = this
;
// overwrite the inherited BOUND_TO method
// with the one we actually need
defineProperty(
self,
BOUND_TO, {
value: function boundTo(callback, remove) {
var
i = cbStack.indexOf(callback),
callback = i < 0 ?
boundStack[
i = cbStack.push(callback) - 1
] = bind.call(callback, self)
:
boundStack[i]
;
// falsy values accepted
// except null or undefined
// so it's true by default
if (remove == false) {
cbStack.splice(i, 1);
boundStack.splice(i, 1);
}
// returns bound callback in any case
// handy to remove listeners and clean stacks
// in one single operation
return callback;
}
}
);
// only the first time, invoe the overwritten method
// use directly latter one every other time
return self[BOUND_TO](callback, remove);
}
}
);
}(Object);
How above snippet is supposed to be used? Here a basic example:
generic.addEventListener("stuff", obj.boundTo(stuff), false);
// ... later on ...
generic.removeEventListener("stuff", obj.boundTo(stuff, 0), false);
// bear in mind that ...
obj.boundTo(stuff) === obj.boundTo(stuff);
// always ... unless we release explicitly the bound function/object
obj.boundTo(stuff, false) !== obj.boundTo(stuff);
// since once removed, the new obj.boundTo call will create a new one
Pros
No need to check, no need to store the bound version, memory leaks safe, no need to do anything extra except calling the method through, and this is needed, the same function.The semantic is straight forward and rather than a yoda condition we have a clear operation that means: return the function created to bind this object as context.
Last, but not least, even if the function was not bound, everything should work as expected, as long as the removeListener generic method has been implemented properly ( checking if the callback/object was attached already )
Cons
Not really, but the function has to be the same. It must be said that two apparently identical functions could be just a copy and paste in two completely different outer scopes. This means that there is no bullet proof way to understand if a function written twice is similar to another one since it is not possible to understand surrounding scopes and it would be silly to do this even on the JS engine level. I am talking about another, unfortunately, common mistake:
// wrong examples ... does not work as expected
generic.addListener("whatever", function () {
return this.whatever;
}.bind(object), false);
// followed by ...
generic.removeListener("whatever", function () {
return this.whatever;
}.bind(object), false);
// or in this proposal case ...
generic.addListener("whatever", object.boundTo(function () {
return this.whatever;
}), false);
// followed by ...
generic.removeListener("whatever", object.boundTo(function () {
return this.whatever;
}), false);
// ... but this is not how JavaScript works ...
Memory speaking, the very first time we use this strategy we create two extra arrays able to speed up operations through indexed function and and bound version per each object. This is inevitable in any case and it's almost exactly the same we do when we address once the bound function.
Once the object has been Garbage Collected, related private arrays will have a reference count equal to zero so the memory should clean up automatically without problems and including all functions bound to that object.
As explained in the example, it is possible in any case to release explicitly bound functions so we can feel like the memory usage is under control.
Why No Arguments
The combination of arguments could be such big number that this technique won't be interesting anymore, specially regarding performances.It does not really make sense to over complicate such basic, most needed, scenario but if you think this is the biggest impediment, then the name should simply be asContextOf so that no ambiguity would be shared with bind native signature.
Update - Preserving Private Methods
Another reason to chose my proposal is the ability to bind proper private methods without using the current instance to store the bound method anywhere ... follow the es-discuss ML to know more but here the stupid, basic, proof of concept:
// stupid useless example ... just as concept
var Counter = (function () {
// private
function increase() {
this.clicks++;
}
function Counter() {
// none out there should be able to retrieve the bound function
document.addEventListener("click", this.boundTo(increase), false);
};
Counter.prototype.clicks = 0;
Counter.prototype.destroy = function () {
// so that only this class scope can control things and nobody else
document.removeEventListener("click", this.boundTo(increase), false);
};
return Counter;
}());
As Summary
I am pretty sure this simple lazy created proposal would be ideal for many frameworks and projects but if I am missing something or if you have any improvement to suggest, I will be more than happy to listen to you.Enjoy simplicity over semantic, this is yet another KISS and YAGNI proposal from this blog.
Subscribe to:
Posts (Atom)