abdelelbouhy Posted July 18, 2013 Share Posted July 18, 2013 (edited) Hi guys, can you please explain how this code is working i'm a bit confuse about the fn.length == arguments.length here the code function addMethod(object, name, fn) { var old = object[name]; object[name] = function(){ if (fn.length == arguments.length){ //this line i don't understand how it works return fn.apply(this, arguments) }else if (typeof old == 'function'){ return old.apply(this, arguments); } }; } var ninjas = { values: ["Dean Edwards", "Sam Stephenson", "Alex Russell"] }; addMethod(ninjas, "find", function(){ return this.values; }); addMethod(ninjas, "find", function(name){ var ret = []; for (var i = 0; i < this.values.length; i++) if (this.values.indexOf(name) == 0) ret.push(this.values); return ret; }); addMethod(ninjas, "find", function(first, last){ var ret = []; for (var i = 0; i < this.values.length; i++) if (this.values == (first + " " + last)) ret.push(this.values); return ret; }); when you call addMethod the first time fn.length == arguments.length is true both are zero that's fine then it execute return fn.apply(this, arguments) the second and third fn.length is 1 then 2 but arguments.length is 0 because no args passed to the anonymous function and it should execute return old.apply(this, arguments); but what happened it execute the first condition so how comes it execute this line even if the lengths are not equal Edited July 18, 2013 by abdelelbouhy Link to comment Share on other sites More sharing options...
thescientist Posted July 18, 2013 Share Posted July 18, 2013 (edited) if you are asking for a code review, (and not to be rude) would be to at least provide the code in the most readable way possible. That would include indented code and posted within [ code ] tags. Edited July 18, 2013 by thescientist Link to comment Share on other sites More sharing options...
abdelelbouhy Posted July 18, 2013 Author Share Posted July 18, 2013 (edited) Sorry mate i fixed the indent my question is how the code calls different functions even if the arguments length is always 0 or i'm missing something Edited July 18, 2013 by abdelelbouhy Link to comment Share on other sites More sharing options...
justsomeguy Posted July 18, 2013 Share Posted July 18, 2013 If you're asking about Function.length, here's what it means: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/length arguments is a variable that is automatically defined in any function, it is the list of arguments that were actually passed to the function. So they are checking if the number of arguments that were actually passed to the function is the same number of arguments that the function expects. It's basically a hack to implement the concept of function overloading that other languages support, where you can define different functions with the same name but different parameter lists, and it will execute the function based on what parameters you pass. arguments.length is not always 0 inside the anonymous function, arguments is the list of actual arguments that were passed. If you call ninjas.find with 2 arguments, it's going to run the function that has 2 arguments defined. It's a weird but clever recursive hack to implement something like function overloading. Link to comment Share on other sites More sharing options...
abdelelbouhy Posted July 18, 2013 Author Share Posted July 18, 2013 (edited) Thank you very much now start to clear it a bit one more thing how the arguments inside the clouser refer to the function that is passed as the argument to the outer function shouldn't arguments inside the inner refer to the arguments of the inner function Edited July 18, 2013 by abdelelbouhy Link to comment Share on other sites More sharing options...
justsomeguy Posted July 18, 2013 Share Posted July 18, 2013 There are several functions here, which aren't always obvious. When you do this: addMethod(ninjas, "find", function(first, last){ var ret = []; for (var i = 0; i < this.values.length; i++) if (this.values[i] == (first + " " + last)) ret.push(this.values[i]); return ret;}); Then inside addMethod: function addMethod(object, name, fn) { var old = object[name]; object[name] = function(){ if (fn.length == arguments.length){ //this line i don't understand how it works return fn.apply(this, arguments) }else if (typeof old == 'function'){ return old.apply(this, arguments); } };} fn is set to the anonymous function that was passed, the one with 2 parameters defined. So, it redefines object[name], which evaluates to ninja.find, as a new anonymous function after saving the old function. Saving the old function makes a closure where every function you pass to addMethod is basically queued up, that's where the recursion comes in. That anonymous function that gets set as ninja.find gets defined several times, once for each call, and they end up in closures. So if you call ninja.find and don't pass any parameters, it's going to execute the anonymous function defined on 2 parameters first, see that the parameter count doesn't match, and then execute old, which is going to be the function that was defined for one parameter, see that the parameters don't match either, and call old again, which is going to be the function defined for no parameters. So it's like a recursive closure stack. But if you call ninja.find and pass 2 parameters, you are calling the anonymous function defined in addMethod. That's the function that you pass the parameters to, so that's what arguments contains. If it finds that fn.length is the same as the number of parameters that was passed, then it calls fn in the same scope and passes it the same arguments that you passed to find (the anonymous function). Hopefully that made sense. Link to comment Share on other sites More sharing options...
abdelelbouhy Posted July 18, 2013 Author Share Posted July 18, 2013 Thank you i was trying to figure it out all day but when i call it the last time with 2 parameters var old should have the previous one the one with 1 parameter instead of the one with no parameter because the object property has the same name find it should be overwritten i know you said it queued up all but how is that if the property name is the same Link to comment Share on other sites More sharing options...
justsomeguy Posted July 18, 2013 Share Posted July 18, 2013 They are still in memory and queued up because before they overwrite the function with a new one, they save the old one in the old variable. That variable containing the old function is still in scope when you're executing the new function, so it's still defined there. It's a confusing chain, but it works. It's pretty clever. Link to comment Share on other sites More sharing options...
abdelelbouhy Posted July 18, 2013 Author Share Posted July 18, 2013 thank you very much mate now i got it all Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now