Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript closure is returning undefined

I have inherited a code base that I need to update for my job. I'm slowly learning what they are trying to accomplish with the closure that is in place, but I am getting stuck when trying to update a part of the site that uses this functionality. I'll give a basic outline of what the code is trying to accomplish and see if anyone can help.

var TheObject = (function (){
    var veryLargeDependantData = {
        var1: {}, 
        var2: {}, 
        var3: [],
        //Set these variables via functions
        function1: function f1(data){...}, 
        function2: function f2(data){...}, 
        initialize: function initialize() { //set values for var1... var3}
     };

     return {initialize: veryLargeDependentData.initialize};
})().initialize(); 

Since I obviously cannot show production code on the site this will have to do. But basically the veryLargeDependentData variable is the entrance to the function. When the page loads it calls the initialize function and everything is happy. But now I need to add this to an onclick event for and older page and the firebug console says that the variable is undefined. In the other pages I am able to use it with no problem.

My question is what magic is going on that causes the closure not to be part of a callable namespace such as this. I'm a bit of a javascript nOOb so I apologize if the question sounds misguided.

onclick='TheObject.initialize();'
like image 610
Michael Guantonio Avatar asked Feb 16 '23 09:02

Michael Guantonio


2 Answers

I assume what you mean is that you want to run the initialize function in a click event handler, and you're currently attempting to do so like this:

TheObject.initialize();

If that's the case, the problem is that TheObject actually refers to the return value of initialize, since you called initialize on the return value of the immediately-invoked function expression. And the chances are that initialize is returning undefined (most likely, it has no explicit return statement).

To solve this, you probably want to remove the immediate call to initalize, which will allow you to use the line shown above both on page load and anywhere else.

like image 181
James Allardice Avatar answered Feb 18 '23 21:02

James Allardice


In this code, the value of TheObject will be whatever the veryLargeDependentData.initialize() method returns. If the initialize method returns nothing, TheObject will be undefined.

A simplified example:

var TheObject = (function () {
  return {
    initialize: function () { 
      // stuff happens here, but importantly, there's nothing returned
    }
  }
})().initialize();

You can break this down into the following order of execution:

// the value of step_one is a function that will return an object when it is run
var step_one = (function () {
  return {
    initialize: function () {
      // ...
    }
  }
});

// after running the function step_one, step_two will be an object
// containing one key - initialize - which is a function
var step_two = step_one();

// since initialize doesn't return anything, TheObject is set to undefined.
var TheObject = step_two.initialize();

You can get around this by setting TheObject to be the object containing the initialize method then run that method again whenever you need it.

var TheObject = (function () {
  return {
    initialize: function () {
    }
  }
})();

// initialize
TheObject.initialize();

// and again
TheObject.initialize();

PLEASE NOTE!

The original author may have intended for the initialize method to only be run once. Running it more than once might introduce bugs into your system!

like image 29
iblamefish Avatar answered Feb 18 '23 23:02

iblamefish