wootscootinboogie
wootscootinboogie

Reputation: 8695

Sharing constructor parameters with closure

I'm trying to understand why one of these versions works and the other does not. Why is it illegal to make the getConfigFails assignment?

var MyClass = (function(){
    var _config;
    function MyClass(config){
        _config = config;
    }
    MyClass.prototype.getConfigWorks = function(){
        _config.getConfigWorks();
    }
    //Uncaught TypeError: Cannot read property 'getConfigFails' of undefined
    MyClass.prototype.getConfigFails = _config.getConfigFails;
    return MyClass;
})();
var myClass = new MyClass({
    getConfigWorks:function(){
        console.log('no errors here');
    },
    getConfigFails: function(){ console.log('fail')}
});

console.log(myClass);

Upvotes: 1

Views: 28

Answers (1)

slebetman
slebetman

Reputation: 113926

You should first note that your constructor is not the (function(){})() function but rather the function MyClass(){} function. The outer self-calling function is there merely to create a closure to make _config private.

Knowing this. It is obvious that the code should also work if we don't care if _config is private should it not? That is, the logic is the same if _config is a global variable.

So, if we can allow _config to be global, you code is exactly the same as this:

var _config;
function InnerClass(config){
    _config = config;
}
InnerClass.prototype.getConfigWorks = function(){
    _config.getConfigWorks();
}
//Uncaught TypeError: Cannot read property 'getConfigFails' of undefined
InnerClass.prototype.getConfigFails = _config.getConfigFails;

var MyClass = InnerClass;

var myClass = new MyClass({
    getConfigWorks:function(){
        console.log('no errors here');
    },
    getConfigFails: function(){ console.log('fail')}
});

console.log(myClass);

Written like this. It is obvious why _config.getConfigFails is undefined. It's because you haven't assigned anything to it.

It's important to remember, that calling new MyClass() merely calls the constructor, not any code surrounding it. Therefore, if you re-wrap the above code in an IIFE the logic doesn't change and only the constructor is called, not the IIFE.

Upvotes: 1

Related Questions