Govind Rai
Govind Rai

Reputation: 15800

What is variable arg referring to in this function? Flow of arguments in Javascript

This is an answer to a SO question:

function typedFunction(paramsList, f){
    //optionally, ensure that typedFunction is being called properly  -- here's a start:
    if (!(paramsList instanceof Array)) throw Error('invalid argument: paramsList must be an array');

    //the type-checked function
    return function(){
        for(var i=0,p,arg;p=paramsList[i],arg=arguments[i],i<paramsList.length; i++){
            if (typeof p === 'string'){
                if (typeof arg !== p) throw new Error('expected type ' + p + ', got ' + typeof arg);
            }
            else { //function
                if (!(arg instanceof p)) throw new Error('expected type ' + String(p).replace(/\s*\{.*/, '') + ', got ' + typeof arg);
            }
        }
        //type checking passed; call the function itself
        return f.apply(this, arguments);
    };
}

//usage:
var ds = typedFunction([Date, 'string'], function(d, s){
    console.log(d.toDateString(), s.substr(0));
});

ds('notadate', 'test');
//Error: expected type function Date(), got string
ds();
//Error: expected type function Date(), got undefined
ds(new Date(), 42);
//Error: expected type string, got number
ds(new Date(), 'success');
//Fri Jun 14 2013 success

It shows a generalized way of ensuring arguments conform to specified types. I am having a hard time grasping the flow of arguments from the ds function call, back to the function that is returned from typedFunction().

Here's what I expect:

Could you explain the logical flow of events/ how this code works?

Sorry if the question is not clear. Please edit the question if you have a grasp of what I'm trying to ask and can make the question easier to read.

Upvotes: 2

Views: 92

Answers (1)

nem035
nem035

Reputation: 35491

For the sake of explanation, assume we name the function being returned as typeChecker:

function typedFunction(paramsList, f){
    // ...
    return function typeChecker() { ... }
}

Now, here's the rundown of what is happening:

Running

var ds = typedFunction([Date, 'string'], function(d, s){
    console.log(d.toDateString(), s.substr(0));
});

binds [Date, 'string'] as paramsList and function(d, s) { ... } as f in the outer environment (closure) of typeChecker. This means typeChecker will, when called, have access to this data via the specified bound variable names paramsList and f.

Then we run:

ds(new Date(), 'success');

which essentially runs typeChecker(new Date(), 'success').

Side note: within any normal JS function (arrow function behaves differently), arguments is a special array-like object provided when the function is called. This object contains all the arguments passed into the function, irrelevant of how many parameters are specified in the function signature.

This means that, when we invoke ds(new Date(), 'success'), arguments conceptually looks like this:

[dateInstance, 'success']

although technically, it looks more like this:

{
  0: dateInstance,
  1: 'success'
}

but this makes no difference in the given code since both structures provide numeric property/index access being used in the for loop.

Therefore, inside typeChecker, arg will refer to the item at the corresponding index in the arguments object for each loop iteration, i.e. arg=arguments[i].

Once the iteration is finished, this runs:

return f.apply(this, arguments);

which calls the function initially given to typedFunction as its second parameter, the one that was bound to the name f in typeChecker's closure, supplying this as the this from within typeChecker and passing along arguments from typeChecker.

Upvotes: 2

Related Questions