srlrs20020 srlrs20020 - 2 months ago 6
Javascript Question

Why can't I call my constructor method within my module?

I have a module called Mole:

var Mole = (function(){

function mole(id){
this.id = id;
}

var randomMole = function(){
var moleIndex = Math.ceil(Math.random() * 8);
var mole = moles[moleIndex];
return mole.id;
}

var score = 0;

var moles = [];

var generateMoles = function(){
for(var i = 1; i <= 8; i++){
var mole = new mole(i);
moles.push(mole);
}
}

return {

init: function(){
//var mole = mole;
generateMoles();
},

randomMole: randomMole,

score: function(){
return score;
},

incrementScore: function(){
score += 1;
}
}


})()


I am calling Mole.init() when the document is ready.

This calls the generateMoles method which uses the mole constructor at the top of the module. Except when the mole constructor is called within my generateMoles function I get this error:

model.js:19 Uncaught TypeError: mole is not a constructor


Why isn't mole a constructor? I defined it as one at the top of the module.

I thought it might be because the mole method was not in the scope of generateMoles when it is called in the init() function, because the init function would create a new closure for generateMoles which would not include the mole constructor. So I tried a work around of defining mole in init function, so it would be included in the closure given to generateMoles..But I still get the same error whether I do this or not.

So now I'm out of ideas why I can't call new mole()..Any help would be greatly appreciated. Thanks.

Answer

var declarations get "hoisted to the top" (i.e. to the outermost scope still within the function see "var hoisting"). Thus your generateMoles is equivalent to:

var generateMoles = function(){
  var mole;
  for(var i = 1; i <= 8; i++){
    mole = new mole(i);
    moles.push(mole);
  }
}

This of course breaks the new mole(i) expression, because mole no longer refers to the mole function, but to the mole variable within that function.

The straightforward solution to this would be to simply use a different name for the local variable, such as m:

var generateMoles = function(){
  for(var i = 1; i <= 8; i++){
    var m = new mole(i);
    moles.push(m);
  }
}