0

I came across the following issue:

function Parent(value) {
     var callback = function() {
         console.log(value);
         //actually the following line was found in the code
         var value; //<- hoisting, takes effect first
     }
     callback();
}

Parent(); //undefined
Parent('Wow!'); //undefined, closure value was lost?!

Both Parent calls logged 'undefined' message, but I really expected to see 'Wow!' value on the second call.

Issue can be reproduced here: http://jsfiddle.net/5tgsj37e/3/

Related question: Why does this closure-scoped variable lose its value?

Community
  • 1
  • 1
Anton Lyhin
  • 1,925
  • 2
  • 28
  • 34
  • 1
    Why do you have `console.log('value');`? Wouldn't this log "value" every time? And is it "undefined" in the console? And, as @charlietfl said, `url` is not defined, so the AJAX may not work at all. Is this your full code? – Jonathan Lam Oct 19 '15 at 21:42
  • 3
    where is `url` defined? Also `Parent()` doesn't return anything so it's not unexpected to have it log undefined. What exactly are you expecting to happen here? – charlietfl Oct 19 '15 at 21:42
  • updated both var url = anyUrl; and console.log(value); – Anton Lyhin Oct 19 '15 at 21:46
  • I can't reproduce it. http://jsfiddle.net/barmar/5tgsj37e/ – Barmar Oct 19 '15 at 21:57
  • It depends on whether your 'anyUrl' is valid, you just put a success callback so if 'anyUrl' is not valid, it won't get executed. – Natural Lam Oct 19 '15 at 21:58
  • @NaturalLam If it doesn't get executed, it won't log `undefined`, either. – Barmar Oct 19 '15 at 21:59
  • 1
    @spirit _"Both Parent calls logged 'undefined' message, but I really expected to see 'Wow!' value on the second call."_ `js` at Question appear to return expected results http://jsfiddle.net/02keLwyp/ – guest271314 Oct 19 '15 at 22:00
  • please, let me check it locally again – Anton Lyhin Oct 19 '15 at 22:08

2 Answers2

2

In this example, Parent has no return statement and thus always returns undefined. Parent also does not itself invoke console.log and therefore does not log anything to the console. The anonymous function created within it and assigned to var callback invokes console.log. This is then passed as a success callback to jQuery.ajax() through your ajaxCall function.

The anonymous callback function will be invoked upon success of the asynchronous ajax request. Success of course according to jQuery documentation for ajax requests.

As the results seem impossible to reproduce with the code as is, perhaps there is additional code in your Parent function somewhere that deletes the value parameter or otherwise sets it to undefined. Parameters and variables closed over by inner functions do not get garbage collected unless they have a 0 reference count.

Nicholas
  • 1,676
  • 12
  • 35
0

The reason was Hoisting:

(function Parent(value) {
     var child = function() {
         console.log(value);
         var value; //hoisting clears closure value
     }
     child();
}('Wow!'));

While is all right:

(function Parent(value) {
     var child = function() {
         console.log(value);
         //var value;
     }
     child();
}('Wow!'));

I did not notice var value in the Parent function yesterday.

Code sample: http://jsfiddle.net/5tgsj37e/3/


Additional notes about the code style.

Strict mode: Putting child outside of parent will create a global. Therefore "use strict" strict mode should be considered as a good practise while using closures.

Explicit closure declaration If you want to use closure value in a child function, it is better to wrap the Child into a closure explicitly. This will prevent global variable creation if one day your child starts living outside of the parent. That will also throw an error that there is no value.

(function Parent(value) {
     (function(childValue) {
         var child = function() {
            console.log(childValue);
         }
         child();
     )(value));
}('Wow!'));

Note about closures: Closure is created per function call, not per function declaration.

Anton Lyhin
  • 1,925
  • 2
  • 28
  • 34