Dan Prince
Dan Prince

Reputation: 29989

What causes this behaviour? (Closures & References)

I have been experimenting with ways to attach methods and variables to an object with self-invoking anonymous functions and come across some behavior that I don't understand.

I define the variable before the function and pass it in as an argument, methods are attached to the reference, but outside, name remains undefined.

var name;
(function(exports) {
    exports = {};
    exports.method = function() {
        // do stuff
    };
})(name);

alert(name === undefined); // true

But when the variable is initialized outside of the function, rather than inside the correct properties are attached as I would expect.

var name2 = {};
(function(exports) {
    exports.method = function() {
        // do stuff
    };
})(name2);

alert(name2 === undefined); // false
alert(name2.method); // method is defined

Why?

Upvotes: 0

Views: 94

Answers (4)

Derek Henderson
Derek Henderson

Reputation: 9706

In the first example, you overwrite the copy of your object with a new object and then assign it a method. That object and method will not be available outside the function.

In the second example, you defined the variable as an object outside of the function and did not overwrite the reference with a new object. Therefore, the method is attached to the object that is passed in.

If you were to create a third example where you define the variable outside the function and then overwrite the reference to it inside of the function --

var name3 = {};
(function(exports) {
    exports = {};
    exports.method = function () {
        // do stuff
    };
})(name);

-- you would find that the method is once again undefined.

console.log(name === undefined); // false
console.log(name.method); // undefined

Upvotes: 2

Kaizo
Kaizo

Reputation: 4185

In the first example "name" and "exports" share a pointer to undefined until you specify that "exports" points to an empty object, but "name" is still pointing to undefined.

In the second example "name" and "exports" share a pointer to an object. Later the object is modified to have a new property, but the pointers are still the same for both vars.

Upvotes: 0

Rune FS
Rune FS

Reputation: 21742

The trick of passing an object from outside the function scope as a parameter to a self executing function is a handy one when it comes to closures and what works with closures is that the reference to the external object (in your first example the reference stored in name) is passed by copy (that is a copy of the reference).

Any changes to the object through the copy of the reference will have effect outside the function E.g. in your second example

exports.method = function() {
    // do stuff
};

adds a method to the object identified by name2. However if you override the reference that the parameter holds as you do in

exports = {}

Then you are simply storing a new reference in the same variable that used to hold the (copy of) original reference

The copying trick is needed at times such as when using closures and iteration variables e.g.

var i;
for(i=0,;i<10;i++){
  setTimeout(function(){console.log(i)},3000);
}

will print 9 ten times whereas

var i;
for(i=0,;i<10;i++){
  setTimeout((function(i){return function(){console.log(i)};})(i),3000);
}

will print 0,1,2,3,4,5,6,7,8,9

Upvotes: 2

Dan Prince
Dan Prince

Reputation: 29989

Because objects are passed by reference, whereas an undefined variable is not.

Upvotes: 3

Related Questions