Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does an object created and returned by a function continue to exist after the function execution ends?

I read that every function has its own stack, which means that when the function ends its variables are no longer kept into the memory. I read also that objects are returned by reference.

Consider this example:

function getObject() {
 var obj = {name: "someName"};
 return obj;
} //At the end the locals should disappear


var newObj = getObject();// Get reference to something that is no longer kept in the stack,
console.log(newObj);//

So if the returned value by the function is a reference to an object that no longer exists (in the stack), how are we still getting the right value? In C (language) to return a pointer to a local variable is insane.

like image 919
Hairi Avatar asked Jan 03 '23 20:01

Hairi


2 Answers

First, a quick disclaimer: There's a difference here between the theory and the optimized process that modern JavaScript engines actually perform.

Let's start with the theory:

The object isn't on the stack, just the variable that contains the reference to the object. The object exists separately, and is created in the heap. So in your example, just before the function returns, we have this in memory:

                    +−−−−−−−−−−−−−−−−−−+
                    |     (object)     |
                    +−−−−−−−−−−−−−−−−−−+
[obj:Ref11254]−−−−−>| name: "someName" |
                    +−−−−−−−−−−−−−−−−−−+

obj, the variable, contains a reference to the object (Ref11254, though of course that's just a conceptual number, we never actually see these). When your function returns, the content of obj (Ref11254) is returned, and obj (the variable) disappears along with the rest of the stack. But the object, which exists separately, continues to exist as long as something has a reference to it — in your case, the newObj variable.

In practice:

As an optimization, modern JavaScript engines frequently allocate objects on the stack (subject to engine-specific size constraints). Then, if the object is going to continue to live after the function terminates and the stack is cleaned up, they copy it into the heap. But if the object isn't going to survive (that is, no reference to it has been kept or is being returned), they can let it get cleaned up along with the stack. (Why? Because stack allocations and cleanup are really fast, and a lot of objects are only used locally in functions.)


It's worth noting that the same question arises for variables if the function creates a function:

function getFunction() {
    var x = 0;
    return function() {
        return x++;
    };
}
var f = getFunction();
console.log(f()); // 0
console.log(f()); // 1
console.log(f()); // 2

Now it's not just that the function getFunction returns (which is an object) survives, but so does x! Even though variables are "on the stack," and the stack gets reclaimed when getFunction returns. How is that possible?!

The answer is that conceptually, local variables aren't on the stack. Putting them on the stack is an optimization (a common one). Conceptually, local variables (along with a few other things) are stored in an object called a LexicalEnvironment object which is created for the call to getFunction. And conceptually, the function getFunction returns has a reference to that LexicalEnvironment object, and so it (and the variables it contains) continues to live on even after getFunction returns. (The function getFunction returns is called a closure because it closes over the environment where it was created.)

And sure enough, in practice modern JavaScript engines don't really do that. They create variables on the stack where it's quick and easy to clean them up. But then if a variable is going to need to live on (like x needs to in our example above), the engine puts it (and any others that it needs to keep around) into a container in the heap and has the closure refer to that container.

More about closures in this question's answers and on my anemic little blog (using slightly outdated terminology).

like image 93
T.J. Crowder Avatar answered Jan 05 '23 10:01

T.J. Crowder


Because the garbage collector is clever than that! Simply put, if the object has active references then it isn't removed. Variables created within the function and not returned are lost when the function ends (unless you've created async calls which use them) but because they then don't have any active references.

See, for example, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management

like image 40
Adam Avatar answered Jan 05 '23 09:01

Adam