Reputation:
I found this question, which helped me a lot and I was able to successfully utilize 2 integers with a settimeout(). However, when passing objects it doesn't seem to work.
Code:
$(document).ready(function() {
var me = {
x: 0,
y: 0
}
var child = {
x: 0,
y: 0
}
function showxydiff(obj1, obj2, when) {
var xdiff = (obj1.x - obj2.x);
var ydiff = (obj1.y - obj2.y);
$('#' + when).append(xdiff + ':' + ydiff + '... ');
};
for (var i = 1; i <= 5; i++) {
child.x = Math.floor((Math.random()*100)+1);
child.y = Math.floor((Math.random()*100)+1);
showxydiff(child, me, 'now');
setTimeout(function (obj1, obj2) {
return function () {
showxydiff(obj1, obj2, 'later');
}
}(child,me), 500);
}
});
And here are the results:
now: 57:37... 98:50... 72:87... 66:31... 28:30...
later: 28:30... 28:30... 28:30... 28:30... 28:30...
Upvotes: 0
Views: 105
Reputation: 3813
Its because of closure. Try this:
$(document).ready(function () {
var me = {
x: 0,
y: 0
};
var child = {
x: 0,
y: 0
};
function showxydiff(obj1, obj2, when) {
var xdiff = (obj1.x - obj2.x);
var ydiff = (obj1.y - obj2.y);
$('#' + when).append(xdiff + ':' + ydiff + '... ');
};
function callTimeout(obj1, obj2) {
setTimeout(function () {
showxydiff(obj1, obj2, 'later');
}, 500);
}
for (var i = 1; i <= 5; i++) {
child.x = Math.floor((Math.random() * 100) + 1);
child.y - Math.floor((Math.random() * 100) + 1);
showxydiff(child, me, 'now');
// create a new object for removing referencing
callTimeout($.extend({}, child), $.extend({}, me));
}
});
Results:
now:
2:59... 6:96... 34:6... 60:3... 71:54...
later:
2:59... 6:96... 34:6... 60:3... 71:54...
Working JSFiddle: http://jsfiddle.net/vTY8U/11/ (using extend of jquery to create a separate object)
http://jsfiddle.net/vTY8U/10/ (create a local child object)
For more info on closure, go through docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures
Upvotes: 0
Reputation: 707258
Your problem is that the same child object is being used for every one of your setTimeout()
calls thus the for
loop modifies the object that all the setTimeout()
callbacks will use. This means they all end up with the same value. This is because objects are passed by reference (no copy is made) so all your callbacks have a reference to the exact same object.
You need to either create a new child object for each setTimeout()
or pass just the .x
and .y
values separately.
for (var i = 1; i <= 5; i++) {
// create new child object for each time through the loop
child = {};
child.x = Math.floor((Math.random()*100)+1);
child.y = Math.floor((Math.random()*100)+1);
showxydiff(child, me, 'now');
setTimeout(function (obj1, obj2) {
return function () {
showxydiff(obj1, obj2, 'later');
}
}(child,me), 500);
}
I also prefer this method of creating the closure (simpler for me to understand):
for (var i = 1; i <= 5; i++) {
// create new child object for each time through the loop
// use more compact javascript literal syntax
child = {x: Math.floor((Math.random()*100)+1), y: Math.floor((Math.random()*100)+1)};
showxydiff(child, me, 'now');
// use an immediately invoking function expression
// to create a closure to capture the current child object reference
(function(obj1, obj2) {
setTimeout(function() {
showxydiff(obj1, obj2, 'later');
}, 500);
})(child, me);
}
Working demo: http://jsfiddle.net/jfriend00/Qbd6V/
Upvotes: 1