views:

62

answers:

3

I want to understand about variables, that has been used in returning function. This is example code

Prototype = {}

Prototype.F =
{
  bind: function()
  {
    var args = arguments, __method = args.shift(), object = args.shift();
    return function()
    {
        return __method.apply(object, args.concat(arguments));
    }
  }
}

function ObjectA()
{
    ...
    this.addListener = Prototype.F.bind(this.eventSource.addListener,
        this.eventSource);
    ...
}


var a = ObjectA();
a.addListener(this); // assuming 'this' here will point to some window object

As I understand the returning function in bind() is not evaluated until it's called in the last line. It's ok to accept. So addListener will hold a function body containing 'apply'.

But what I don't understand, when addListener is called, what kind of parameters it is going to have? particularly _method and args will always be uninitialized?

+1  A: 

The function that bind returns is a closure over the arguments to the bind function, and so the __method argument will be the first argument to bind (in your example call, that will be the this.eventSource.addListener function).

Closures are basically functions that have data bound into them intrinsically. Here's a simpler example:

function makeAlert(msg) {
    return function() {
        alert(msg);
    }
}
var myalert = makeAlert("Hi there!");
myalert(); // Alerts "Hi there!"

The function returned by makeAlert "closes over" (retains access to) the things in scope within the makeAlert function call that created it, including the msg argument. That's why when we call the function later, it still has msg even though the call to makeAlert has long since completed. More about closures here.

A key thing to remember about closures is that they retain access to everything that's in scope where they're defined, not just the things they they're obviously using. So for instance:

function init() {
    var data;

    data = /* ...build some really big array of data...*/;

    document.getElementById('foo').onclick = function() {
        this.style.display = "none";
    };
}

Even though the event handler has nothing to do with the big data array, it keeps a reference to it, and so keeps that data in memory after the call to init has completed. This is because the link that it has is to a behind-the-scenes object (loosely called the "variable object") that is a container for all of the arguments and local variables in scope where it's defined. (In this particular case, if you don't need all that data, just set data to undefined at the end. The event handler will still have a reference to data, but that reference isn't holding the array anymore, so the array's memory can be reclaimed.)

T.J. Crowder
So in other words if js engine will detect any function that might be used in future, it will save the scope for later usage, so whenever the time comes to call it, that function can have some scope to work with and it was decided by js designers, that scope to be the one that function has been created in. Just wondering if that scope is immutable? For example can I undefine `data` in the inner function? Moreover, undefine `data` from somewhere else, by accessing scope?
Michael
@Michael: The variable object, like all objects in Javascript, will get garbage-collected if nothing has a reference to it; the function is an object with a reference to the variable object, which keeps the variable object from being GC'd. As long as something has a reference to the function, that keeps the function from being GC'd, which keeps the variable object from being GC'd. You get the idea. :-) The contents of (property names in) the variable object are determined by the code; what those point to can be changed as with anything else, by assigning values to them. So (cont'd)
T.J. Crowder
@Michael: (continuing) So if you wanted the array pointed to by `data`, but only once, you could assign `undefined` to it on the first use of the inner function. Or, more usefully, if (say) you have a `count` member in the outer function, you can increment it in the inner function. Things like that. (Check out the linked article on my blog for more.)
T.J. Crowder
A: 

_method and args will be always initialized, because you are defining them when you first call

this.addListener = Prototype.F.bind(this.eventSource.addListener, this.eventSource);

There, you'll get that _method will be that this.eventSource.addListener, and args will be those both arguments.

Seb
A: 

in the scope of a function, arguments is an array-like object which contains the values provided when the function is called, whether or not the function definition has parameters defined.

so for this call:

Prototype.F.bind(this.eventSource.addListener, this.eventSource);

which leads to this:

var args = arguments, __method = args.shift(), object = args.shift();

arguments contains 2 items: whatever this.eventSource.addListener and this.eventSource point to when the function is called. that collection of 2 items is copied to args, and then the items are moved from the colleciton to __method and object.

since the call bind actually generates another function, the arguments instance in the new function will be different- it'll have the parameters provided at the time of that call. the original arguments from the call to bind are saved in args and combined with arguments from the later function call.

lincolnk