Reputation: 20992
Suppose I have the following jQuery code:
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);
});
});
Currently, because do_something
is inside of the function where link
is defined it has access to that variable (closure). However, I'm wondering whether it's possible to avoid creating the function for every link. I'd rather do something closer to this:
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);
});
});
So that do_something
is only created once. However, if I do this, then do_something
no longer has a value for link
.
Assume in this case that it's not possible to change the code for FooBar
and that it expects just a callback and can't send along any additional parameters.
The only alternative I've thought of is something like this, which at least only creates functions as needed:
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));
});
});
Is that the best option?
Upvotes: 3
Views: 242
Reputation: 39250
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.
Upvotes: 0
Reputation: 14134
Here you go:
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);
});
In case you have something async and slow ongoing, you can try to make it lazy like do_something_maker or the bind/$.proxy approach, but only once for each link (on the first click and add it to $.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);
});
Upvotes: 2
Reputation: 2571
You can use 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));
});
});
Upvotes: 0
Reputation: 47172
Just for the kicks:
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);
What has this given you?
Well for each FooBar
object you create you will have 1 less instance of zizzle
(since all functions are objects you effectively have 1 less).
For each instance of Util
, you will have 1 less instance of do_something
AND you can now decide better when you want a Util
instance and not clutter the global object with an unused function.
This works because we're defining one function on the prototype instead of letting the functions run rampant in a object literal {}
or attach them to the global namespace
Upvotes: 0
Reputation: 17906
Why not just passing "link" as an argument to your zizzle function and pass it to the callback ?
sth like :
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);
});
Upvotes: 0