views:

166

answers:

4
var foo = (function() {
    var proxy = {},
        warning = false;

    proxy.warn = function(msg) {
        if (!warning) {
            warning = true;
            alert(msg);
        }
        return this; //For the purpose of method chaining we return proxy object.
    }

    function func() {
        alert(warning); //This is a private function relative to foo.
    }

    return proxy;
}());

foo.warn(); //will alert
foo.warn(); //will not alert since warning has been set to true

I am confused about instantiation here since new keyword is not used who is holding the value of warning? Is there any leak here in terms of the scope warning lives in.

Thank you.

+1  A: 

This answer to another question really helped me expand my understanding of how javascript objects work:

http://stackoverflow.com/questions/1007340/javascript-function-aliasing-doesnt-seem-to-work/1162192#1162192

As for your code snippet, let's break it down. Start by looking at the high-level structure: var foo = ( exrpession );. You could just as easily say: var foo = expression;, but IIRC the parentheses are needed to handle an IE-specific quirk.

Now, in this case the expression is an anonymous function. Javascript is perfectly fine with you defining a function with no name. Just don't expect to call it unless you save a reference some where. You can also call an anonymous function immediately after the declaration, like this:

function() {
     alert('test');
     return 42;
}();

This should look suspiciously similar to the basic structure used for the expression from your code snippet. Hopefully you can easily see that the 42 from my sample could just as easily be an object.

So the question remains, why would you do this? Remember that in javascript, functions are also objects. As a good student of OOP, you probably like to make some members of your objects private. However, javascript doesn't have anything built-in to support this. Fortunately, it just happens that if you return an object from that inner function it will have access to other variables defined in that function, but outside code will not have any way to access them. So you have, in effect, created an object with private members.

Joel Coehoorn
@Joel: I've updated the code to show why such a private variable is needed in my case. Thanks.
Jeffrey C
+2  A: 

Well a live in the top closure function function() {....

foo is holding the proxy object you are returning, it means that everything who are not in this proxy object are private and cant be accessed from foo. If you want to get the value of a you can add a new function returning a =>

proxy.getValueOfA=function(){return a}

then you can call foo.getValueOfA()

As a remark:

var proxy={}

is the short form of var proxy=new Object() so there is an instanciation.

Patrick
The `var proxy = {}` code uses something called compact object notation. It's a shortcut and does not need `new` anywhere to create an object.
Joel Coehoorn
As Joel Coehoorn says {} is equivalent to new Object() as [] is equivalent to new Array()
Patrick
+1  A: 

Both proxy.method and func have access to a via the closure property. For more information about scope and objects, check out this article that surfaced recently: A Concise, Executable Guide to JavaScript Objects, Variables, Functions, and Prototypes

The code that you've posted fits what's known as the "module pattern" and is becoming a very popular way to define objects in JavaScript as it makes private variables and methods easy to create (by taking advantage of the closure property as mentioned earlier).

Justin Johnson
+1  A: 

this

    return proxy;
}());

should be this

    return proxy;
})();

and this

function() {
     alert('test');
     return 42;
}();

does not work ... syntax error. you should try your code before you put it on here. pretty sure you meant this:

(function() {
     alert('test');
     return 42;
})();

also, that fact that you're returning a private member kind of defeats the whole point of scope closure, but it'll work...

var foo = (function() {
    var proxy = {}, // private
    proxy.warn = function(msg) {
    ...
    return proxy; // publicly accessible

it's the same as

var foo = { warn: function(){ /* code */ } };
Dan Beam
@Dan: why do you say "defeats the whole point of scope closure", i want to hold a private switch so that alert should be fired or not.
Jeffrey C
yes, you are right, this would do this. perhaps I did not look into what you were trying to do, just how you were doing it. either way, a var inside an anonymous function will be private, so it can only be accessed by public or protected members. I'm used to returning my public members in the return statement (this way you separate your private/protected members visually / logically.window.foo = (function(){ var warning = true; return( { warn: function( msg ){ return( warning ? alert( msg ) : this ); } } );})();
Dan Beam