mplungjan
mplungjan

Reputation: 177701

Specific closure/scoping issue in jQuery

I so often run into this pattern.
Can someone please give me a canonical way of only getting image1 once - if you look at example two, it works - but I fail to understand why. An explanation of this specific situation is appreciated, I have read the closure stuff on the net :)

Initial code:

$(document).ready(function() {
  $("#prev, #next").click(function() {
    var mainImage = $("#image1");
    if (mainImage.css("visibility")=="hidden") {
      $(mainImage.css("visibility","visible");
      return;
    }
    var currentNumber = parseInt(mainImage.attr("src").split('gallery/')[1]); 
    var newNumber = ($(this).attr("id")=="next")?currentNumber+1:currentNumber-1;
    var testImage = new Image();
    testImage.onload=function() {
      var img = $("#image1");
      img.attr("src",this.src);
      img.css("visibility","visible");   
    }
    testImage.onerror=function() {
      $("#image1").css("visibility","hidden");   
    }
    testImage.src="gallery/"+newNumber+".jpg";
    return false;
  });
});

Attempting a closure - why does it work - or is this just a scoping issue?

$(document).ready(function() {
  $("#prev, #next").click(function() {
    var mainImage = $("#image1"); // this should be local to the click function
    if (mainImage.css("visibility")=="hidden") {
      $(mainImage.css("visibility","visible");
      return;
    }
    var currentNumber = parseInt(mainImage.attr("src").split('gallery/')[1]); 
    var newNumber = ($(this).attr("id")=="next")?currentNumber+1:currentNumber-1;
    var testImage = new Image();
    testImage.onload=function() {
      mainImage.attr("src",this.src); // how come mainImage is available here?
      mainImage.css("visibility","visible");   
    }
    testImage.onerror=function() {
      mainImage.css("visibility","hidden");// how come mainImage is available here?
    }
    testImage.src="gallery/"+newNumber+".jpg";
    return false;
  });
});

Upvotes: 0

Views: 71

Answers (3)

Simeon
Simeon

Reputation: 5579

This is how JavaScript scoping works. Take a look at the following:

var func1 = function(){
    console.log(i + 2);
};

var myFunc = function(){
    var i = 1;
    var func2 = function(){
        console.log(i + 2);
    };
    func2(); // output 3
    func1(); // ReferenceError: i is not defined
};

Upvotes: 1

Edgar Villegas Alvarado
Edgar Villegas Alvarado

Reputation: 18344

In javascript, vars live in the scope of the function where it has been defined, and the 'subfunctions' (local functions) inside this function.

For example:

function fun1(){
   var var1 = "Defined in fun1. ";
   function fun2(){
      var var2 = "Defined in fun2. ";
      alert(var1); //Alerts "Defined in fun1 "
      function fun3(){
          alert(var1 + var2); //Alerts "Defined in fun1. Defined in fun2";
      }
   }
   alert(var2); //Alerts 'undefined' (fun1 doesn't know var2 exists)
}

And the same is happening in your code. Your variable mainImage 'lives' in every local function. Don't forget that binded functions are also local functions, even if they don't have name or are declared differently.

Hope this helps. Cheers

Upvotes: 1

Ergec
Ergec

Reputation: 11824

mainImage is defined with var so it becomes global for all functions

Upvotes: 0

Related Questions