5

I was reading Secrets of the JavaScript Ninja and I saw this code which produces a function overload:

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);
        };
}

function Ninjas()
{
        var ninjas = ["Dean Edwards", "Sam Stephenson", "Alex Russell"];
        // addMethod is defined in Listing 2-28
        addMethod(this, "find", function ()
        {
                return ninjas;
        });
        addMethod(this, "find", function (name)
        {
                var ret = [];
                for(var i = 0; i < ninjas.length; i++)
                if(ninjas[i].indexOf(name) == 0) ret.push(ninjas[i]);
                return ret;
        });
        addMethod(this, "find", function (first, last)
        {
                var ret = [];
                for(var i = 0; i < ninjas.length; i++)
                if(ninjas[i] == (first + " " + last)) ret.push(ninjas[i]);
                return ret;
        });
}

var ninjas = new Ninjas();


assert(ninjas.find().length == 3, "Finds all ninjas");
assert(ninjas.find("Sam").length == 1, "Finds ninjas by first name");
assert(ninjas.find("Dean", "Edwards").length == 1, "Finds ninjas by first and last name");
assert(ninjas.find("Alex", "X", "Russell") == null, "Does nothing");

function assert(a,b)
{
  if (a==true) console.log(b) ; else console("----");
}

As far as I understand, the addMethod always keeps the old value of the function (via closure).

So finally, there is one function which checks a condition, and if it fails, it invokes the old function which in turn does the same thing.

However I don't understand the evaluation of arguments.length (I know the differences between function().length and argument.length).

To which rectangle does arguments refer to?

enter image description here

I tracked it in debugger, and I'm getting confused because at first, the function registers (so arguments.length is 3 [(object, name, fn)], but later it is invoked so now there are another arguments.

How is that working?

JSBin

1

1 Answer 1

5

But does arguments refers to : (which rectangle ?)

The 2nd -- object[name] = function ()

arguments will always refer to the object for the inner-most function declaration/expression. The arguments of any outer functions, such as addMethod(object, name, fn), will be shadowed and rendered inaccessible since they all use the same identifier.


It's comparing the number of arguments that were named (fn.length) to the the number of arguments passed in (arguments.length), using the 1st match. So that:

ninjas.find()                       // (0 == 0), uses `function ()`
ninjas.find("Sam")                  // (1 == 1), uses `function (name)`
ninjas.find("Dean", "Edwards")      // (2 == 2), uses `function (first, last)`
ninjas.find("Alex", "X", "Russell") // (? == 3), no match, returns `undefined`
Sign up to request clarification or add additional context in comments.

9 Comments

+1 It might be worth mentioning that at first time (ninja.find()), sees the 3 overload function and then activates the 2 overload function and when it still doesnt find it , it goes again....and again...
@RoyiNamir Well, it doesn't activate the "overloads" directly until it has a match. It's only calling the anonymous function created within addMethod. This acts as a kind of linked-list loop of old references, climbing down a "rabbit hole" of closures until it either finds a match or reaches the bottom.
The this in fn.apply(this referes to the object in object[name] ={..} right ?
@RoyiNamir this will be ninja because the 1st is called as ninja.find(...) and keeps passing the reference to ninja along with old.apply(...).
I had the same confusion with regard to what arguments was referring to? The point to consider is that while fn.length is fixed during function definition (compile time), arguments.length is evaluated only during a function call. And if arguments.length can match any fn.length during a particular run, then it calls that function else move onto the other function calls until it finally runs dry.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.