Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to understand closures. Could somebody walk me through this code?

Here's a bit of javascript taken from this reddit post:

function Stream() {
    var data       = [],
        listeners  = [];

    function push( new_data ) {
        var result = data.push( new_data );
        callListeners( new_data, result );
        return result;
    }

    function addListener( listener ) {
        return listeners.push( listener );
    }

    function callListeners( ) {
        var length    = listeners.length,
            result    = [],
            action    = null;
        while ( length-- ) {
            action = listeners[ length ];
            result.push( action.apply( null, arguments) );
        }
        return result;
    }

    return {
        push : push,
        addListener: addListener
    }

}


var foo = Stream();
foo.addListener( function( new_data ) {
    alert( "added: " + new_data );
});
foo.push( "Hello World!" );

I think I have a tenuous grasp on Closures after reading this tutorial, but I just can't figure out how this code works. When I try to parse it in my head, I basically get stuck at line 6: var result = data.push( new_data );.

It seems with data simply being an array at that point data.push( foo ) doesn't make sense. And wouldn't it recurse infinitely anyway? (strike that -- didn't know there was a native push method for arrays) Very next line callListener is called with two parameters, but below the function has none.

If someone's got a few minutes, could you grab my hand and walk me through this code like the ignorant dolt I am? Right now, I'm not even sure I understand the destination.

like image 755
Greg Avatar asked Feb 04 '26 13:02

Greg


1 Answers

Arrays are objects, and they have a push() method. Nothing unusual there.

The callListeners() function doesn't declare any named parameters, but JavaScript allows functions to be called with more parameters than they're declared to take, and the full list of arguments is available as the special name arguments. callListeners() uses arguments in an action.apply() call, to invoke the action function with the same list of arguments that callListeners() itself was given. The purpose of callListeners() is that you call it with some arguments, and it calls all the functions in the listeners array with those arguments.

Neither of those things is really related to the use of closures, though. The place where closures come into play is that the object returned by Stream() has two methods, push() and addListener(), that can "see" the same data and listeners arrays even though those arrays aren't stored in the object that the methods are called on. Two calls to Stream() will return two objects whose methods see different data and listeners arrays.

like image 55
Wyzard Avatar answered Feb 06 '26 04:02

Wyzard