Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Puzzling Javascript constructor issue

Tags:

javascript

A very puzzling problem i am having with JavaScript. look at the code below..

az={
   classes:{
      test:function(){
        this.hello=function(name){
          alert('hello '+name);
        }
      }
   },
   getClass:function(name){
    return az.classes[name];
   }
};
var a=new az.classes['test']();
a.hello('foo');
var b= new az.getClass('test')();
b.hello();// fails !!!

in the code if you notice we have a class defined inside an object az.classes. when try to create an instance of that class by new az.classes['test](), it works and a.hello() executes fine. but when i call the method az.getClass('test'), which in turn returns the same constructor, but it fails when i say var b=new az.getClass('test'); here its saying b is undefined!! and b.hello() fails!! i do not understand this behaviour! what is the difference between new az.classes['test']() and new az.getClass('test'). Are they not the same thing??

like image 864
user1179563 Avatar asked Apr 24 '13 05:04

user1179563


2 Answers

When instantiating a constructor, the first parens indicate what to use at the constructor.

So new az.classes['test'](); will execute the expression az.classes['test'] and use the resulting function as the constructor.

Or refactored, it does this:

// new az.classes['test']()
//                       ^ expression left of here used as constructor!
var MyConstructor = az.classes['test'];
new MyConstructor();

However, new az.getClass('test')(); executes the expression az.getClass which returns your class getter function, and attempts to use that as the constructor. Then your instance tried to be executed with the ().

Or refactored, it does this:

// new az.getClass('test')();
//                ^ expression left of here used as constructor!
var MyConstructor = az.getClass;
var instance = new MyConstructor('test');
instance(); // obviously not gonna work.

See the difference?

You can solve this by wrapping more parens around the expression that should return the constructor:

new (az.getClass('test'))();
//                       ^ expression left of here used as constructor!

Or by saving the constructor reference to a local variable, and then using it on the next line. This is probably more sane and readable:

var MyConstructor = az.getClass('test');
new MyConstructor();
//               ^ expression left of here used as constructor!
like image 168
Alex Wayne Avatar answered Nov 09 '22 13:11

Alex Wayne


A constructor function in JavaScript can return a value, which replaces the value which would normally be returned by the "new" expression.

So new az.getClass("test")() will first evaluate az.getClass("test") which will return a function. You are then invoking that function with () which will return undefined since it has no return value.

like image 27
john_omalley Avatar answered Nov 09 '22 12:11

john_omalley