views:

35

answers:

3

Hi there, can anyone explain the following to me. I have two JavaScript functions defined in global scope as follows:

    var foo = function () {
        var that = this;

        that.toString = function () { return "foobar" };

        return that;
    }();

    alert(foo.toString());

    var foo2 = function (foo) {
        var that;

        that = $.extend(true, {}, foo);

        return that;
    }();

Alerting foo.toString() works as I would expect as foo is assigned the result of invoking the function. However I would have expected foo2 to have access to foo. Yet inside foo2 foo is undefined. Can anyone help?

Many Thanks, Mike.

+2  A: 

You've created a function which accepts an argument called foo. This local variable will override the global variable of the same name. If you don't pass in anything for this argument, the local foo is automatically set to undefined. You can either remove the argument or pass the global foo.

var foo2 = function (foo) {
    var that;

    that = $.extend(true, {}, foo); // foo is from the local scope

    return that;
}(foo); // Pass in foo

Or

var foo2 = function () { // remove the argument
    var that;

    that = $.extend(true, {}, foo); // foo is from the global scope

    return that;
}();
Andy E
Thanks Andy - a v.clear explanation.
Godders
Andy, in general is there a preference between the two options you present?
Godders
@Godders: you would usually opt for using the outer scope variable, unless there's a chance the variable could be changed by the outer scope before it's used in the inner scope, in a timer callback function. Put simply, use the second option if you're not accessing the variable from a timer function or AJAX *onreadystatechange* event handler.
Andy E
@Godders: just to add for completeness' sake: in functions where speed optimization is important, you can better use the first variant: accessing local variables is generally (a tiny bit) faster than accessing global variables. That said, with this closure thing I'm not so sure it is.
Marcel Korpel
+1  A: 

foo is undefined in foo2 because you're defining a local foo as a parameter:

var foo2 = function (foo) { ...

and you're then calling foo2 with no arguments:

}();
RichieHindle
A: 

You are making foo2 create another variable called foo inside its scope, with a value of undefined. If you want access foo, use:

var foo2 = function (foo) {
  //code
}(foo);

or access it from the window object:

window.foo
digitalFresh