NLV
NLV

Reputation: 21641

Javascript scope issues with Revealing Module Pattern

One more JavaScript scoping problem. I believe this is not related to 'hoisting'.

I've a small block of code here - http://jsfiddle.net/0oqLzsec/2/

var c = function(){
    var x = 'before',
        callBefore = function(){
            alert(x);
        },
        callAfter = function(){
            _callAfter();
        };

    return{
        callBefore : callBefore,
        callAfter : callAfter
    }

    var y = 'after';

    function _callAfter(){
        alert(y);
    }
};

var obj = c();
obj.callBefore();
obj.callAfter();

callAfter() always alerts 'undefined' even if the variable y is defined before _callAfter(). But If I move the variable y declaration before variable x it is working.

I'm wondering if callAfter() can _callAfter() which is defined below, why can't it read variable y?

Upvotes: 1

Views: 148

Answers (2)

Ruan Mendes
Ruan Mendes

Reputation: 92274

It is related to hoisting, var y is moved to the top of the function, but the assignment (y = 'after') is not, so it never runs because it's after the return statement.

The JS engine rewrites your code to look something like:

var c = function(){           
    // functions also get hoisted to the top
    function _callAfter(){
        alert(y);
    }
    var x = 'before',
        callBefore = function(){
            alert(x);
        },
        callAfter = function(){
            _callAfter();
        },
        // y declaration is hoisted to the top of the function
        y;

    return {
        callBefore : callBefore,
        callAfter : callAfter
    };

    // the assignment never gets called because it's after the return
    y = 'after';
};

Upvotes: 2

Phrogz
Phrogz

Reputation: 303215

_callAfter and y are both hoisted, which makes them known as local variables through the function invocation. The _callAfter function is able to be called (as you do), and it also closes over the variable y. However, this variable does not get a value assigned before you return from the c function. Thus, you get undefined. It is the same if you put var y; BEFORE the return, and y='after'; after the return.

In other words, the following two are equivalent:

function foo(){
  var a;
  return function(){ return a };
  a = 42; // never runs
}
alert( foo()() );

function bar(){
  return function(){ return a };
  var a = 42;
}
alert( bar()() );

Here's an example showing that the local variable is hoisted and closed over, even when the function literal occurs before the var in code:

function build() {
  return function(newValue) {
    alert("was: " + oldValue);
    oldValue = newValue;
    alert("now: " + oldValue);
  }
  var oldValue = 42;
}

f = build();
f(17);
// was: undefined
// now: 17

f(99);
// was: 17
// now: 99

Upvotes: 3

Related Questions