简体   繁体   中英

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 ox(5) should throw an error, but it executes. Why?

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 = {} . ox will continue to refer to that function. The o object has no knowledge of the math variable.


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

oy 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 oy(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 .


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

I don't understand why you would expect an error on ox .

At the start, when we define math = { ... } , we have two functions.

The first function is referenced both by its name fact , and by the object property math.fact

The second function is anonymous, and is referenced only by math.fact1

We then "copy" the functions into o . At this point, the first function is referenced by all of fact , math.fact and ox , while the second function is referenced by math.fact1 and oy .

We then destroy the math object by replacing it with a new, empty object. At this point, the first function is referenced by fact and ox , and the second only by oy .

Now we actually call the functions. ox contains a recursive call to fact , which is very clearly still defined as that function. However, oy contains a recursive call to math.fact1 , which we destroyed, hence an error there.

This has nothing to do with... well, anything of interest. The function that names something that still exists continues to work, while the function that names something that doesn't exist any more fails.

I mean... duh...

ox is a reference to a function (object). Because of this reference, the fact function will keep existing after the math object has been reset (objects only get garbage collected when no reference to them exist anymore).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM