Clev3r
Clev3r

Reputation: 1588

Javascript closure confusion

Can someone explain why this occurs in Javascript?

var singleton = window.singleton || {};
singleton.methods = (function () {
    var _private = function() {
        console.log('outer private function');
    }

    return {
        _private: function() {
            console.log('inner private');
        },

        public: function() {
            _private();
        }
    }
})();

singleton.methods.public();

My intuition leads me to believe that calling .public() should log 'inner private'. It doesn't. If I change the public() definition to this._private() I get what I would expect. Why?

Upvotes: 1

Views: 80

Answers (4)

Alex Shilman
Alex Shilman

Reputation: 1547

What you have is a closure. When you return a function in a closure, that function(s) becomes exposed, hence "public". Every function inside the closure preserve its true private scope. So when you call _private(); from public function, you are actually calling the inner function. Your public _private() belongs to the constructor, to call that you should apply a proper chain to it. Like so:

this._private()

Upvotes: 0

Guffa
Guffa

Reputation: 700870

The function that logs inner private is a property in an object. The property can't be reached by only using its name, you have to specify that it's in the object.

In object oriented languages like C# and Java the scope of a method contains the identifiers from the object, but it doesn't work like that in Javascript. It only has function scope (and global scope), so you can't access object members without specifying which object they belong to.

Upvotes: 0

Denys Séguret
Denys Séguret

Reputation: 382474

You have a scope problem : _private in your public function refers to the one defined in the constructing closure (a closure is defined by a function call, the block you return doesn't define a scope).

If you want to log the _private method of the object you return, change the definition to

return {
    _private: function() {
        console.log('inner private');
    },

    public: function() {
        this._private();
    }
}

Here's what the MDN says about closures :

In short, variables from the parent function of the closure remain bound from the parent's scope.

To resolve _private in the public function, you have to search in order

  1. in the public function itself
  2. in the immediately outer scope, that is the closure you use to build the methods object. The function is found there
  3. if it weren't found the outer scope (which might be the global one) would be searched in turn

Upvotes: 2

David P. Caldwell
David P. Caldwell

Reputation: 3839

My guess is that you're coming from a language like Java where this. is implied inside a method of an object when referring to an unqualified member name. In JavaScript, it's not, and that's the root of your problem.

The only exception in JavaScript is that the top-level scope -- window in the browser -- is treated specially. If I declare var foo = "bar" at the top level, it creates a property of window called foo with the value "bar" and hence will appear to behave the way you're expecting:

this.foo = "bar";
alert(foo); // shows bar
alert(this.foo); // also shows "bar"

But in general, outside the top-level scope, this is not true. So your function named public is looking for a scope variable called _private, and the property of the same object called _private -- this._private -- is not a scope variable in that or any other scope.

Upvotes: 0

Related Questions