我应该避免创建这个JavaScript闭包吗?

时间:2012-12-05 11:47:13

标签: javascript jquery closures performance

这可能有点抽象,但我正试图解决JavaScript闭包等问题。请使用以下代码:

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

传递给它的匿名函数绑定到click事件会创建一个引用me的闭包。我想知道的是,做这样的事情是否更好(避免关闭):

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

这是一个更好的方法,还是我过于偏执于创建一个闭包?或者,是否有“第三条道路”?


修改

此外,做这样的事情会更好:

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

4 个答案:

答案 0 :(得分:1)

匿名函数现在在javascript中大量使用(作为参数和作用域/闭包的直接函数)。这没有性能问题。

但是你可能会遇到代码阅读问题。因为当您看到变量时,必须检查变量的来源。但这里没什么大不了的。

在你的第二个例子中,你仍然有一个关闭“休息”。因为在click中的匿名函数中,您使用localMe变量。 localMe是你的功能之外的一个论点。

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

如果你真的想避免关闭“break”,你应该将你的函数绑定到你的对象。但请注意,并非每个浏览器都支持函数的bind方法。

答案 1 :(得分:1)

后者(AFAIK)效率更高,但可能无法测量,除非在紧密循环中使用。

原因是所有变量解除引用都必须遵循范围链。在后一种情况下,变量localMe可以在匿名函数的参数列表中找到。

在前一种情况下,在那里找不到变量,但在外部范围内。遍历范围链需要额外的时间。

答案 2 :(得分:1)

如果从构造函数绑定事件,您将始终创建一个闭包。实际上,您甚至需要闭包来保留对实例的引用。但是,您可能会这样做:

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

如果你只创建构造函数的单例实例,那么无论如何都无关紧要。

答案 3 :(得分:0)

我可能会这样做:

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

这会使用 .apply 来跳过闭包和使用Ies的用法。不确定它是否更有效,但它是另一种选择。