I'm currently studying Secrets of the JavaScript Ninja by John Resig and I'm hoping someone can help me further understand one of the examples.
It is a function that allows method overloading on an object, each overload has it's own definition and behaviour. He blogged about it here.
The code looks like this:
function addMethod(object, name, fn) {
var old = object[name];
object[name] = function(){
if (fn.length == arguments.length)
return fn.apply(this, arguments)
else if (typeof old == 'function')
return old.apply(this, arguments);
};
And used like this:
addMethod(obj,'funcName',function(){});
addMethod(obj,'funcName',function(a){});
addMethod(obj,'funcName',function(a,b){});
I think I understand most of how this works but you can get a better explanation than I can give from the blog post above).
However, it accesses the value of old
and fn
using closures, which I'm still studying.
EDIT - added jsFiddle
below.
When trying to understand it, I realised that the line return fn.apply(this, arguments)
could be simply return fn()
with what seems to be the same result. See an example in this jsFiddle.
So, Why is it using the apply
syntax if not required?
I have tried playing with the example in jsFiddle without apply and it always seems to wo
Also, what exactly is happening when we return those functions, especially in the case of:
return old.apply(this, arguments);
I really want to get a solid understanding of not just how to use this method but why it works so any insight would be greatly appreciated.
Thanks
So, Why is it using the
apply
syntax if not required?
It is actually required for the usage.
this
and arguments
are different for every function
and are set when they're called. By using fn()
, fn
will be called with an empty arguments
collection or no value passed for this
.
.apply(this, arguments)
calls fn
or old
and passes along the values for both from the current function
.
var obj = {};
addMethod(obj, 'funcName', function (a, b) {
console.log(this === obj);
console.log(a, b);
console.log(arguments[0], arguments[1]);
});
obj.funcName(2, 3);
// true
// 2, 3
// 2, 3
Also, what exactly is happening when we return those functions, especially in the case of:
return old.apply(this, arguments);
Well, the purpose of addMethod
is to create a chain of functions where each knows about and can call the old
function created before it.
For the example from the book, the chain is built as:
// after: addMethod(obj, 'funcName', function(){});
obj.funcName = function(){...} ──> function(){}
// after: addMethod(obj, 'funcName', function(a){});
obj.funcName = function(){...} ──────> function(a){}
└── function(){...} ──> function(){}
// after: addMethod(obj, 'funcName', function(a,b){});
obj.funcName = function(){...} ──────────> function(a,b){}
└── function(){...} ──────> function(a){}
└── function(){...} ──> function(){}
Legend:
`└──` represents an `old` reference
`──>` represents a `fn` reference
Each function(){...}
is a unique instance created by reevaluating the same expression in a different scope/closure:
function(){
if (fn.length == arguments.length)
return fn.apply(this, arguments)
else if (typeof old == 'function')
return old.apply(this, arguments);
}
Each .apply()
then follows an "arm" or "arrow" to either an old
or fn
and the return
s allow the result to be passed back through / in reverse.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With