Search code examples
javascriptfunctionclosuresfunction-expression

why does the named javascript function persist?


This is an adaptation of what you'd find in john resig's Learning Advanced Javascript app.

var math = {
    fact: function fact(n){
        return n > 0 ? n * fact(n-1): 1;
    },
    fact1: function (n) {
        return n > 0? n * math.fact1(n-1) : 1;
    }
};

console.log(math.fact(5));  // 120
console.log(math.fact1(5)); // 120

var o = {
    x: math.fact,
    y: math.fact1
};

math = {};

console.log(o.x === undefined); // false
console.log(o.y === undefined); // false
console.log(o.x(5));            // 120
console.log(o.y(5));            // Uncaught TypeError: math.fact1 is not a function

One would expect o.x(5) should throw an error, but it executes. Why?


Solution

  • When an object literal expression is evaluated, the expression to the right of each colon is evaluated and assigned to the specified property.

    So when this executes:

    var o = {
        x: math.fact,
        y: math.fact1
    };
    

    the expression math.fact is evaluated, and the result is the function that math.fact is referring to at that time.

    The same goes for math.fact1.

    So even if you reassign the math variable with math = {}. o.x will continue to refer to that function. The o object has no knowledge of the math variable.


    The reason why o.y(5) throws an error has to do with closures.

    o.y refers to this function:

    function (n) {
         return n > 0? n * math.fact1(n-1) : 1;
    }
    

    You can see here that it uses the math variable. Even if you reassign the math variable, this function will continue to refer to the variable itself.

    When you call o.y(5), the function executes, but when it tries to call math.fact(n-1), that fails, because math no longer has a property called fact.


    o.x does not have the problem that o.y has. It is a named function, and therefore is able to continue to call itself even after math is reassigned.