tags:

views:

56

answers:

4

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);
A: 

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

this.someString in your example.

Sebastián Grignoli
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
True. I realized that and was about to delete my own answer, but your explanation made it worth staying. :)
Sebastián Grignoli
Can you explain it a little more? I didn't get the 'this' stuff still!
Sriram
@Sriram, @Sebastián, give a look to [this question](http://stackoverflow.com/questions/3320677/this-operator-in-javascript/3320706#3320706).
CMS
+5  A: 

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:

CMS
Is there a work around for this?
Sriram
@Sriram - Change variable names, or pass in the outer variable as an argument.
Peter Ajtai
@CMS - Your drawing broke :(
Peter Ajtai
@Peter, Hmm pretty strange I see it properly on FF, OP, and CH...
CMS
@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
@Peter - http://img217.imageshack.us/img217/1934/75980192.jpg
Sriram
@Peter, must be the bold text, removed...
CMS
@CMS - Very nice; it looks perfect now.
Peter Ajtai
A: 

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
You never call `innerfunc()` only the outer one.
Peter Ajtai
`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.
CMS
http://jsfiddle.net/tjYz5/
Peter Ajtai
Oh thanks, that means most of my answer is actually false I guess.
thomasrutter
You're welcome, you can check [this question](http://stackoverflow.com/questions/3345365/and-i-thought-i-understood-scope) for more details. :)
CMS
+1  A: 

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.

Peter Ajtai