1

When using the following code:

var x = 5;
setTimeout(function() {
    console.log(x);
}, 2500);
x = 10;

the output is 10, and I totally understand why.

However, I would like the output to be 5 in the above example ( or more specifically the value of x when the set timeout function is called, not the value at the time the callback is called. )

One option that has been suggested to me is to call out to a function and look up the data.

something like this:

var x = 5;
var value_of_x_at_some_time = function() {
    return old_value_of_x;
}

setTimeout(function() {
    console.log(value_of_x_at_some_time());
}, 2500);
old_value_of_x = x;
x = 10;

I understand the idea, however this would mean I would need to go through an array and calculate what is the correct value. This may be the right way, but doesn't feel right to me.

I am writing some software to manage scheduling events, (using node-schedule), For example, I could have an AngularJS front end that sets a particular time/length of an event, and some other information of it.

It's possible that I could have 2 events at that same time, so when I look it up in that function I would need to have a way to know which one to use (assuming I have two "alarms", if you will, setup, one callback would need to know to use blah[x] and one would need to know to use blah[x+1] for example).

I could look up current time and find the closest time that is already past then marking if I set it to do whatever was required and that might work, but I was wondering if there was a way to wrap the current state of the variables I use up as part of the (anonymous?) function.

Basically I am writing a DVR app in nodejs, I'm connecting to Firebase to manage persisting data, and AngularJS on the front end, so I can keep most of the app disconnected, I am trying to use node-schedule, so when I add a recording event in angular, I can see the data change in firebase, schedule the event, and when the callback fires start recording the appropriate show, my concern is I could have two shows set to record at the same time, and I have to manage recording them correctly, and one possible idea I have is a data structure such as this:

var recording_event = {
    time: "1500",
    date: "01012015",
    length: "3600", //time in ms
    channel: "51",
    program: "1",
    scheduled: "true",
    recording: "false"
}
var blah[] = recording_events....

Then search through the array blah in the called function.

var lookup_value() {
    // loop through blah[] till you find the event closest to current time,
    // check if recording is true, if not
    // set the value of recording to true
    // else search for the next matching event
    // assume x is the index that matches correctly
    // finally return the event
    return blah[x];
}

setTimeout(function() {
    var temp = lookup_value();
    // set tuner to temp.channel
    // set tuner to temp.program
    // start recording for length of time temp.length
}, 2500);

However this seems like I am doing more work then I need to, in my mind I would expect to just push this data as part of the function, so basically replace the above function with the below:

temp = x //"newly secheduled event"
setTimeout(function() {
    // set tuner to temp.channel (value at the time of the scheduling)
    // set tuner to temp.program (value at the time of the scheduling)
    // start recording for length of time temp.length (value at the time of the scheduling)
}, 2500);

more or less dynamically at runtime. Is there some way to do this?

(Also I have no idea if this is a good title, I'm open to suggestions).

thefourtheye
  • 233,700
  • 52
  • 457
  • 497
onaclov2000
  • 5,741
  • 9
  • 40
  • 54
  • Same basic idea: http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example – epascarello Jan 06 '15 at 05:42

2 Answers2

4

Just addressing the top part of your question:

var x = 5;
(function(currentX) {
    setTimeout(function () {
                    console.log(currentX);
            }, 2500);
})(x);
x = 10;

will display 5.

EDIT: All of what Felix Kling said. Note that while we create a function at different levels, the end effect is the same - the important point is that a function exists, to introduce a new scope, with a new variable that is disconnected from the original x.

EDIT2: Guys, go upvote Felix's answer a bit more, even if I beat him originally by 10 seconds, his is by now definitely the better of the two answers, not fair he only has my upvote :D

Amadan
  • 191,408
  • 23
  • 240
  • 301
3

I didn't read everything in detail, but I guess you want to create a new scope to capture the current value of your variable. Functions create scope and an easy way to create and call a function is to use an IIFE:

var x = 5;
setTimeout((function(y) {
  // this function is executed immediately and passed the current value of `x` 

  return function () {
   // this is function that is passed to setTimeout
   // since every function is a closure, it has access to the IIFE parameter y

   console.log(y);
  };
}(x)), 2500);
x = 10;

See also: JavaScript closure inside loops – simple practical example

However, there is an even simpler option: You can bind a specific value to a parameter of a function using .bind:

setTimeout(function(y) {
    console.log(y);
}.bind(null, x), 2500);

.bind creates a new function and sets this and parameters to the specific values you pass to it.

Community
  • 1
  • 1
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • I had read about bind a little bit ago, but I guess I didn't understand it quite enough, this appears to work for what I'm hoping to do. Also I've read about closures in the past, but never had an occasion to use them, so didn't even cross my mind. – onaclov2000 Jan 06 '15 at 06:03
  • So reading the above IIFE (which I think I may have read about earlier this evening as well i believe) we call a function immediately, and that returns a function with the value (inside) set by the calling function.... – onaclov2000 Jan 06 '15 at 06:06