0

This may be a bit abstract but I'm trying to get my head round JavaScript closures etc. Take the following code:

function MyObj() {
    var me = this;

    this.foo = function(bar) {
        // Do something with 'bar'
    }

    // Set up lots of local variables etc.
    // ....

    $(window).load(function() {
        // Add a delegated click handler to specific <input> elements
        $(document).on('click.myobj', 'input.special', function() {
            // Do something with the <input> that triggered the click event
            me.foo(this);
        });
    });
}

var myObj = new MyObj();

The anonymous function passed to that is bound to the click event creates a closure that references me. What I want to know is whether it's better to do something like this instead (to avoid the closure):

$(window).load(function() {
    // Add a delegated click handler to specific <input> elements
    (function(localMe) {
        $(document).on('click.myobj', 'input.special', function() {
            // Do something with the <input> that triggered the click event
            localMe.foo(this);
        });
    })(me);
});

Is this a better approach, or am I being overly paranoid about creating a closure? Alternatively, is there a "third way"?


EDIT

Additionally, would it be better to do something like this:

$(window).load(function() {
    // Add a delegated click handler to specific <input> elements
    $(document).on('click.myobj', 'input.special', {localMe : me}, function(event) {
        // Do something with the <input> that triggered the click event
        event.data.localMe.foo(this);
    });
});
2
  • What do you try to gain by that? Commented Dec 5, 2012 at 11:51
  • @Philipp, I'm under the impression that creating JavaScript closures can be expensive, as extra data is required to keep track of the scope etc. In this example I accept that the savings may be minimal, but I want to know if this method is better in principle. Commented Dec 5, 2012 at 11:54

4 Answers 4

1

The latter is (AFAIK) more efficient, but probably not measurably so unless used in a tight loop.

The reason is that all variable dereferencing must follow the scope chain. In the latter case, the variable localMe can be found in the anonymous function's parameter list.

In the former case, the variable isn't found there, but in the outer scope. This traversal up the scope chain takes extra time.

Sign up to request clarification or add additional context in comments.

Comments

1

Anonymous functions are massively used in javascript now (as arguments and as an immediate function for scopes/closures). There's no performance problem with that.

But you can have a problem of code reading maybe. Because when you see a variable, you must check where the variable is from. But no big deal here.

And in your second example, you still have a closure "break". Because in your anonymous function in the click, you use the localMe variable. And the localMe is an argument of a fonction outside of your fonction.

// Here, 'me' is a direct local variable.
$(window).load(function() {
    // Here, we are in an anonymous fonction, so 'me' is not a direct variable anymore. But you still can access it.

    // Add a delegated click handler to specific <input> elements
    (function(localMe) {
        // Here, 'localMe' is a direct local variable.
        $(document).on('click.myobj', 'input.special', function() {
            // We are in an anonymous function, so 'localMe' is not a direct variable anymore.

            // Do something with the <input> that triggered the click event
            localMe.foo(this);
        });
    })(me);
});

If you really want to avoid a closure "break", you should bind your function to your object. But note that not every browser support the bind method on functions.

2 Comments

No, localMe is a parameter to the inner function, and so is implicitly available in the closest possible scope.
ah yes - I forgot about the inner callback function. I was looking just at the anonymous function.
1

You will always create a closure if you bind the event from the constructor. In fact, you even need the closure to preserve the reference to your instance. However, you might do something like this:

function MyObj() {
    this.foo = function(bar) {
        // Do something with 'bar'
    }

    // Set up lots of local variables etc.
    // ....
}

var myObj = new MyObj();
$(function() {
    $(document).on('click.myobj', 'input.special', function() {
        myObj.foo(this);
    });
});

If you do only create a singleton instance of your constructor, it won't matter anyway.

Comments

0

I would probably do it this way:

var bind = function( fn, me ) { return function() { return fn.apply(me, arguments); }; },
    Object = (function() {
        function Object() {
            this.handler = bind(this.handler, this);
            // Add a delegated click handler to specific <input> elements.
            $(document).on("click.myobj", "input.special", this.handler);
        }

        Object.prototype.foo = function( bar ) {
            // Do something with "bar".
        };

        Object.prototype.handler = function( event ) {
            // Do something with the <input> that triggered the click even.
            return this.foo(event.currentTarget);
        };

        return Object;
    })();

var obj = new Object();

This skips the uses of closures and iifes, using .apply instead. Not sure if it is more efficient or not, but it is another option.

1 Comment

bind isn't a good option for event handlers because in those this is supposed to represent the clicked object, not an externally bound variable.

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.