A
Asen Bozhilov
Today i see couple of slides produced by John Resig. One of the
interesting code is addMethod to implement method overloading.
<URL: http://ejohn.org/apps/learn/#89 >
function addMethod(object, name, fn){
// Save a reference to the old method
var old = object[ name ];
// Overwrite the method with our new one
object[ name ] = function(){
// Check the number of incoming arguments,
// compared to our overloaded function
if ( fn.length == arguments.length )
// If there was a match, run the function
return fn.apply( this, arguments );
// Otherwise, fallback to the old method
else if ( typeof old === "function" )
return old.apply( this, arguments );
};
}
That method for my is excellent example for how *closures* can be
harmful. Assigned function to property have [[scope]] property which
refer Activation/Variable of current execution context. `old' property
of Activation/Variable contains previous value of that property. So
that produce long chain of Activation/Variable objects which isn't
marked for garbage collection on end of execution context.
e.g.
var foo = {};
addMethod(foo, 'bar', function(a){});
addMethod(foo, 'bar', function(a, b){});
addMethod(foo, 'bar', function(){});
1. inner function refer Activation/Variable from [[scope]] property
2. `old' refer function from step 1. inner function[[scope]] refer
ActivationVariable
3. `old' refer function from step 2. Activation/Variable which been
referred from inner function created in that execution context.
4. `bar' property of `object' who referred from `foo' will be refer
inner function created in step 3.
Who want design like this? If i have trusted to John Resig, maybe i
use that code, but for my this is junk. I don't like at all that idea
to emulate something which isn't supported from language native, but
someday if i want method overloading definitely i will be use
something like this one:
function Foo()
{
this._overloaded = {};
};
Foo.prototype = {
addMethod : function(name, fn)
{
if (!this._overloaded[name])
{
this._overloaded[name] = [];
this[name] = function()
{
var arg_len = arguments.length,
fn = this._overloaded[name][arg_len];
if (fn) return fn.apply(this, arguments);
}
}
if (fn instanceof Function)
{
this._overloaded[name][fn.length] = fn;
}
}
};
var foo = new Foo();
foo.addMethod('bar', function(){return 0;});
foo.addMethod('bar', function(a){return 1});
foo.addMethod('bar', function(a, b){return 2;});
window.alert(foo.bar()); //0
window.alert(foo.bar(10)); //1
window.alert(foo.bar(10, 20)); //2
Regards.
interesting code is addMethod to implement method overloading.
<URL: http://ejohn.org/apps/learn/#89 >
function addMethod(object, name, fn){
// Save a reference to the old method
var old = object[ name ];
// Overwrite the method with our new one
object[ name ] = function(){
// Check the number of incoming arguments,
// compared to our overloaded function
if ( fn.length == arguments.length )
// If there was a match, run the function
return fn.apply( this, arguments );
// Otherwise, fallback to the old method
else if ( typeof old === "function" )
return old.apply( this, arguments );
};
}
That method for my is excellent example for how *closures* can be
harmful. Assigned function to property have [[scope]] property which
refer Activation/Variable of current execution context. `old' property
of Activation/Variable contains previous value of that property. So
that produce long chain of Activation/Variable objects which isn't
marked for garbage collection on end of execution context.
e.g.
var foo = {};
addMethod(foo, 'bar', function(a){});
addMethod(foo, 'bar', function(a, b){});
addMethod(foo, 'bar', function(){});
1. inner function refer Activation/Variable from [[scope]] property
2. `old' refer function from step 1. inner function[[scope]] refer
ActivationVariable
3. `old' refer function from step 2. Activation/Variable which been
referred from inner function created in that execution context.
4. `bar' property of `object' who referred from `foo' will be refer
inner function created in step 3.
Who want design like this? If i have trusted to John Resig, maybe i
use that code, but for my this is junk. I don't like at all that idea
to emulate something which isn't supported from language native, but
someday if i want method overloading definitely i will be use
something like this one:
function Foo()
{
this._overloaded = {};
};
Foo.prototype = {
addMethod : function(name, fn)
{
if (!this._overloaded[name])
{
this._overloaded[name] = [];
this[name] = function()
{
var arg_len = arguments.length,
fn = this._overloaded[name][arg_len];
if (fn) return fn.apply(this, arguments);
}
}
if (fn instanceof Function)
{
this._overloaded[name][fn.length] = fn;
}
}
};
var foo = new Foo();
foo.addMethod('bar', function(){return 0;});
foo.addMethod('bar', function(a){return 1});
foo.addMethod('bar', function(a, b){return 2;});
window.alert(foo.bar()); //0
window.alert(foo.bar(10)); //1
window.alert(foo.bar(10, 20)); //2
Regards.