Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript: What happens to objects that don't have a name?

Tags:

javascript

If I do the following (in the global scope):

var myObject = {name: "Bob"};

I have a way to point to that object in memory (i.e. the string identifier "myObject)". I can open the console and type: myObject.name and the console will respond with:

"Bob"

Now, if I just type:

{name: "Jane"};

I'm creating that object somewhere and I'm guessing it goes on living in some scope. Is there any way I can find it? Does it exists under window somewhere in some generic store?

Edit: Some people are saying it will just get garbage collected.

So how about this example:

var MyObject = function(){
    $("button").click(this.alert);
}

MyObject.prototype.alert = function(){
    alert("I heard that!")
}

new MyObject();

It can't be garbage collected because its callback is bound to a DOM event. Where does the resulting object live and can it be accessed?

like image 403
Matt Harrison Avatar asked Mar 24 '23 09:03

Matt Harrison


2 Answers

If there is no reference pointing to this object (that is you didn't assign it to any variable or to the value of any property), then there is no way to access it and in fact it's no living as the garbage collector can reclaim this memory immediately.

like image 158
Denys Séguret Avatar answered Apr 07 '23 07:04

Denys Séguret


The short answer is no, the object isn't kept alive in memory somewhere you can't reach. Bit life is live: the truth is a bit more complicated, but not by much, if you grasp the basics.

Update:
In response to your update: you're right, in a way. The callback is a reference to MyObject.prototype.alert, which you accessed using this.alert, but that function object is being referenced by a constructors prototype, and can't be GC'ed anyway. The instance itself is not involved in the alert function itself, so it can be GC'ed safely.

Think of it like this:

MyConstructor.prototype.alert = 0x000123;//some memory address
   ||
   \/
0x000123 = [object Function];

The function object itself isn't directly attached to anything, it floats there in memory, and is being referenced by the prototype. When you create an instance:

new MyConstructor().alert;

Is resolved as follows:

[new MyConstructor instance] allocated at e.g 0x000321
   ||
   \\
    \=>[alert] check for alert @instance -> not found
          \\
           \=> check prototype, yield 0x000123 <-- memory address, return this value

So upon executing the statement:

 $("button").click(this.alert);

this.alert is an expression that is resolved to 0x000123. In other words, jQ's click method (function object) only receives the memory address of the alert function object. The instance, or indeed the constructor isn't involved at all. That's why this, or the call-context, can change depending on how and where a function is invoked. see here for more on ad-hoc context determination

I'll even do you one better:

/*assume your code is here*/
new MyConstructor().alert = function(){ alert('I am deaf');};
MyConstructor.prototype.alert = 'foo';
$('#button').click();

Guess what, the click event alert "I heard that" all the same, the prototype isn't even involved, let alone the instance.
If MyConstructor were to go out of scope, the click event will still work fine, because the GC still sees a reference to the alert function object that isn't out of scope yet. everything else is available for GC'ing, though...


The JS garbage collector (GC) is a flag-and-swipe GC. When the JS engine encounters your statement, it does allocate the memory required to store your object. When the next statement is reached, that object will probably still be in memory.
Every now and then, the GC X-checks all the objects it sees in memory, and tries to locate all references to that object that are still accessible. When it comes across the object literal that was just created in that statement, but no reference to was assigned, the object is flagged for garbage collection.
The next time the GC gets about its business of swiping flagged object, that object will be removed from memory.

Of course, this isn't entirely true for all engines. suppose your statement was written in an IIFE, that returned a function:

var foo = function()
{
    {name: 'bar'};
    return function()
    {
        return 'foobar';
    };
}());

Some engines just keep the entire scope of the IIFE in memory, and only deallocate the memory for that scope when the return value of the IIFE goes out of scope (is flagged for GC). Other engines, like V8 last time I checked, will in fact flag those objects/vars of the outer scope that aren't referenced by its return value.
Though, come to think about it, it might not apply to this case, because the GC might even kick in even before the IIFE returns... But on the whole, that's just nit-picking.

There's also the question of logical OR's to consider:

var name = (mayNotExist || {name:'default'}).name;

In this case, if mayNotExist does exist, the object literal will never even be created, thanks to JS's short-circuit evaluation of expressions.

A couple of links on the matter:

  • Objects and functions in javascript
  • javascript - How to make this code work?
  • What makes my.class.js so fast?
  • Properties of Javascript function objects
like image 36
Elias Van Ootegem Avatar answered Apr 07 '23 07:04

Elias Van Ootegem