3

假设我有以下 jQuery 代码:

var FooBar = {
    zizzle: function (callback) {
        var x, y, z;
        // … do stuff with x y and z
        callback(z, y, z);
    }
}

$("a[href]").each(function () {
    var link = this;

    // do things with the link, e.g. 
    $(link).data('fiddle', "deedee")

    function do_something() {
        console.log("I would use the link variable here:", link)
        // lots of code here using link
        // blah, blah, blah link
    }

    $(this).click(function () {
        FooBar.zizzle(do_something);
    });
});

目前,因为do_something在定义的函数内部,link它可以访问该变量(闭包)。但是,我想知道是否可以避免为每个链接创建函数。我宁愿做一些更接近这一点的事情:

var FooBar = {
    zizzle: function (callback) {
        var x, y, z;
        // … do stuff with x y and z
        callback(z, y, z);
    }
}

function do_something() {
    console.log("I would use the link variable here:", link)
    // lots of code here using link
    // blah, blah, blah link
}

$("a[href]").each(function () {
    var link = this;

    // do things with the link, e.g. 
    $(link).data('fiddle', "deedee")

    $(this).click(function () {
        FooBar.zizzle(do_something);
    });
});

所以do_something它只创建一次。但是,如果我这样做,则do_something不再具有link.

假设在这种情况下无法更改代码,FooBar并且它只需要一个回调并且不能发送任何其他参数。

我想到的唯一选择是这样的,至少只根据需要创建函数:

var FooBar = {
    zizzle: function (callback) {
        var x, y, z;
        // … do stuff with x y and z
        callback(z, y, z);
    }
}

function do_something_maker(link) {
    return function (x, y, z) {
        console.log("I would use the link variable here:", link)
        // lots of code here using link
        // blah, blah, blah link
    }
}

$("a[href]").each(function () {
    var link = this;

    // do things with the link, e.g. 
    $(link).data('fiddle', "deedee")

    $(this).click(function () {
        FooBar.zizzle(do_something_maker(link));
    });
});

那是最好的选择吗?

4

5 回答 5

2

干得好:

var FooBar = {
    zizzle: function (callback) {
        var x, y, z;
        // … do stuff with x y and z
        callback(z, y, z);
    }
}

function do_something() {
    console.log("I would use the link variable here:", do_something.link);
    //if no link exists, abort
    if(!do_something.link){return;}
    //code with do_something.link


    //you might want to delete afterwards
    //delete do_something.link;
}

$("a[href]").click(function () {
    do_something.link = this;
    FooBar.zizzle(do_something);
});

如果你有一些异步且运行缓慢的东西,你可以尝试像 do_something_maker 或 bind/$.proxy 方法一样让它变得懒惰,但每个链接只有一次(第一次单击并将其添加到 $.data)。

var FooBar = {
    zizzle: function (callback) {
        var x, y, z;
        // … do stuff with x y and z
        callback(z, y, z);
    }
}

function do_something() {
    console.log("I would use the link variable here:", this);

}

$("a[href]").click(function () {
    var fn = $.data(this, 'zizzleCB') || $.data(this, 'zizzleCB', do_something.bind(this));
    FooBar.zizzle(fn);
});
于 2013-11-12T21:15:20.450 回答
0

You should register click on the container of the elements you're interested in. In your case that would be document.body. Then have an extra selector figure out when to take action: http://api.jquery.com/on/ Here is an example

function create_do_something($link){
  return function(z,y,x){
    do_something(z,y,x);
  };
}
$(document.body).on("click","a[href]",function () {
  var $link =  this;
  FooBar.zizzle(create_do_something($link));
});

Just found out something, if you have any solution using $("a[href]").click or $("a[href]").on jQuery will create a closure for every found element in the selector.

Running some tests in Chrome and doing a heap snapshot has the following result:

No jQuery and no JS code:

2557 closures

No code at all (just jQuery and jQuery ui):

5832 closures

With the following code

$(document.body).on("click","div"
  ,function(){console.log("hi");});

5834 closures(with 2 divs)

5834 closures(with 100 divs), notice that the amount of closures stays the same

With the following code

$("div").click(function(){console.log("hi");});

5835 closures(with 2 divs)

5933 closures(with 100 divs), notice there are 98 closures more so jQuery adds a closure for you on every found element in the selector.

So why does $("div").click have more closures?

jQuery 1.10.2 unminified on line 4762:

 eventHandle = elemData.handle = function( e ) {

When you set a break point there you'll see jQuery add a closure for each element found in the selector. So $("div") returned a hundred where $(document.body) has one no matter how many divs.

于 2013-11-13T04:53:40.240 回答
0

只是为了踢球:

var Util = function() {};
Util.prototype.do_something = function() {};

var FooBar = function() {
};
FooBar.prototype.zizzle = function(fn) {};

var fooBar = new FooBar();
var util = new Util();
fooBar.zizzle(util.do_something);

这给了你什么?

那么对于您创建的每个FooBar对象,您将少 1 个实例zizzle(因为所有函数都是对象,所以您实际上少了 1 个)。对于 的每个实例Util,您将减少 1 个do_something AND 的实例,您现在可以更好地决定何时需要一个Util实例,而不是用未使用的函数弄乱全局对象。

这是可行的,因为我们在原型上定义了一个函数,而不是让函数在对象字面量中猖獗地运行{}或将它们附加到全局命名空间

于 2013-11-12T21:23:53.700 回答
0

您可以使用 Function.prototype.bind:

var FooBar = {
    zizzle: function (callback) {
        var x, y, z;
        // … do stuff with x y and z
        callback(z, y, z);
    }
}

function do_something() {
    console.log("'this' refers to link here", this)
    // lots of code here using link
    // blah, blah, blah link
}

$("a[href]").each(function () {
    link = this;
    $(this).click(function () {
        FooBar.zizzle(do_something.bind(link));
    });
});
于 2013-11-12T21:25:53.233 回答
0

为什么不将“链接”作为参数传递给您的 zizzle 函数并将其传递给回调?

某事喜欢:

var FooBar = {
    zizzle: function (callback,link) {
        var x, y, z;
        // … do stuff with x y and z
        callback(x, y, z, link);
    }
}

function do_something(x, y, z, link) {
    console.log("I would use the link variable here:", link)
    // lots of code here using link
    // blah, blah, blah link
}

$("a[href]").on("click", function () {
    FooBar.zizzle(do_something, this);
});
于 2013-11-12T21:08:23.267 回答