5

I took this from Google Code Playground http://code.google.com/apis/ajax/playground/

/*CLOSURE
* When a function is defined in another function and it
*    has access to the outer function's context even after
*    the outer function returns
* An important concept to learn in Javascript
*/

function outerFunction(someNum) {
  var someString = 'Hai!';
  var content = document.getElementById('content');
  function innerFunction() {
    content.innerHTML = someNum + ': ' + someString;
    content = null; // IE memory leak for DOM reference
  }
  innerFunction();
}

outerFunction(1);

///////////////////////

Its all ok, but if I have a local variable in the inner function with the same name as a variable in the outer function then how to access that variable?

function outerFunction(someNum) {
  var someString = 'Hai!';
  var content = document.getElementById('content');
  function innerFunction() {
    var someString='Hello';
    content.innerHTML = someNum + ': ' + someString;
    content = null; // IE memory leak for DOM reference
  }
  innerFunction();
}

outerFunction(1);
Sriram
  • 1,180
  • 2
  • 15
  • 27
  • I inserted a line var ss=someString; inside the innerfunction. Then when I tried to access ss it returned undefined – Sriram Aug 13 '10 at 06:48
  • Very similar / duplicate? question: http://stackoverflow.com/questions/1484143/scope-chain-in-javascript – Peter Ajtai Aug 13 '10 at 06:59

5 Answers5

8

You can't, because the variable of the outer scope is shadowed by the one on your inner function.

The scope chain on the innerFunction looks something like this:


  innerFunction                     outerFunction             global object
 ______________________         ________________________        _______________
|* someString = 'Hello'| <---- |  someString = 'Hai!'    | <---|* outerFunction|
 ----------------------        |* content = [HTMLElement]|     |    .....      |
                               |* someNum (argument)     |      ---------------
                               |* innerFunction          |
                                -------------------------

* Denotes a resolvable identifier from the scope of innerFunction.

Each function has its own Variable Object, is where the identifiers of Function Declarations, Variable Declarations, and function Formal Parameters live, as properties.

Those objects are not directly accessible by code, the scope chain is formed by all those chained objects.

When an identifier is resolved, the lookup goes up in the scope chain, looking for the first appearance of it, until the global object is reached, if the identifier is not found, a ReferenceError is thrown.

Give a look to the following articles:

Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
  • @Sriram - Change variable names, or pass in the outer variable as an argument. – Peter Ajtai Aug 13 '10 at 06:58
  • @CMS - Huh - Here's Chrome: http://a.imageshack.us/img401/2914/chromez.jpg - Looks pretty much the same in FF for me also. – Peter Ajtai Aug 13 '10 at 07:15
  • @CMS - Very nice; it looks perfect now. – Peter Ajtai Aug 13 '10 at 07:33
  • +1 Thanks @CMS. Just what I was looking for. For some reason I thought that a variable declaration could shadow a formal parameter (both within the same function), but now I see they're all properties on the same Variables Object. Now it makes sense why altering `arguments[0]` also altered the variable that had the same name as the parameter. I much prefer the *strict mode* behavior where I can tweak the arguments object without affecting the params. Thanks again. – user113716 Sep 15 '11 at 23:43
2

The local variables of the closure "shadow" the variables of the same name from the outer function, so this:

function outerFunction(s) {
  var someString = 'Hai!';
  function innerFunction() {
    var someString='Hello';
    alert(someString);
  }
  innerFunction();
}
outerFunction();

will alert Hello.

The only way to work around it is to rename your variables, or pass in the variable you want to work with:

function outerFunction(s) {
  var someString = 'Hai!';
  function innerFunction(outer) {
    var someString='Hello';
    alert(outer);
  }
  innerFunction(someString);
}
outerFunction();        

Will alert Hai!

To learn about the scope chain, take a look at this previous scope question.

Community
  • 1
  • 1
Peter Ajtai
  • 56,972
  • 13
  • 121
  • 140
0
function outerFunction(someNum) {
var someString = 'Hai!';
var content = document.getElementById('content');
function innerFunction() {
this.someString = 'Hello'; 
content.innerHTML = someNum + ': ' + someString;
content = null; // IE memory leak for DOM reference
 }
    innerFunction();

} outerFunction(1);

Gaurav
  • 11
  • 1
0

Try with this.varname to refer to the one in the closure.

this.someString in your example.

Sebastián Grignoli
  • 32,444
  • 17
  • 71
  • 86
  • 1
    The meaning of the `this` variable depends on how the inner is called, so this will only work if the function containing the closure scope is the context from which the inner function was called as a method. If you pass that function to some other object and then call it, even though the link to the closure is still there, the `this` will not point to it. – thomasrutter Aug 13 '10 at 06:50
  • True. I realized that and was about to delete my own answer, but your explanation made it worth staying. :) – Sebastián Grignoli Aug 13 '10 at 06:52
  • Can you explain it a little more? I didn't get the 'this' stuff still! – Sriram Aug 13 '10 at 07:01
  • @Sriram, @Sebastián, give a look to [this question](http://stackoverflow.com/questions/3320677/this-operator-in-javascript/3320706#3320706). – Christian C. Salvadó Aug 13 '10 at 07:08
0

You could

  • simply avoid creating any local variable with the same name, or
  • make a local copy of that closure variable before declaring the local variable of the same name (if you really want a local variable of the same name)

(had a workaround but removed it after it was pointed out that it wouldn't actually work)

thomasrutter
  • 114,488
  • 30
  • 148
  • 167
  • You never call `innerfunc()` only the outer one. – Peter Ajtai Aug 13 '10 at 07:05
  • 1
    `copyofmyvar` will be always `undefined`, the Variable Instantiation process takes place *before* the actual function execution, the variables encountered in scope are initialized with `undefined` and this happens with the `myvar` defined in the inner scope, is added to the Variable Object and initialized with `undefined`, later, the function executes and makes the assignments and by that time `myvar` from the outer scope is already shadowed. – Christian C. Salvadó Aug 13 '10 at 07:10
  • 1
    Oh thanks, that means most of my answer is actually false I guess. – thomasrutter Aug 13 '10 at 07:24
  • You're welcome, you can check [this question](http://stackoverflow.com/questions/3345365/and-i-thought-i-understood-scope) for more details. :) – Christian C. Salvadó Aug 13 '10 at 07:35