Search code examples
javascriptnode.jsconstructorthisinstance

Constructor fails on second time, but not first


I have the following code:

var foo = function () {
    foo = this;
    foo.boo = function () {
        console.log("boo");
    }
}

var bar = new foo().boo();
var baz = new foo().boo();

This code executes the first creation of an instance of foo, but fails at the second with the following output:

boo
/Users/BaranSkistad/Code/example.js:9
var baz = new foo().boo();
          ^

TypeError: foo is not a constructor
    at Object.<anonymous> (/Users/BaranSkistad/Code/example.js:9:11)
    at Module._compile (module.js:573:30)
    at Object.Module._extensions..js (module.js:584:10)

    at Module.load (module.js:507:32)
    at tryModuleLoad (module.js:470:12)
    at Function.Module._load (module.js:462:3)
    at Function.Module.runMain (module.js:609:10)
    at startup (bootstrap_node.js:158:16)
    at bootstrap_node.js:578:3

Why is this script failing? I know it has something to do with setting foo to this on line 2, instead of just using this, but why is it problematic?

var foo = function () {
    self = this;
    self.boo = function () {
        console.log("boo");
    }
}

var bar = new foo().boo();
var baz = new foo().boo();

If I set self to equal this, it passes, why is this so?


Solution

  • The problem is in the following line

    foo = this;
    

    The above line misses the variable declaration. So foo will refer to the global variable foo which is a constructor.When you call the function first time the line executes and foo is changed to this(instance of the foo)

    In the second case the code also creates a global variable self which will be equal to this. But in that case it will not change constructor because the names are different.

    The solution to this is to make foo a local variable by using let(or const/var).

    var foo = function () {
        let foo = this;
        foo.boo = function () {
            console.log("boo");
        }
    }
    
    var bar = new foo().boo();
    var baz = new foo().boo();