You need to understand Javascript object references

I am reviewing this piece of code from John Resig's site. I don't understand, when ninja object is set to empty object, yell method is still available for samurai.

Is it because since there is still a link lying around the ninja, this is not garbage collection?

var ninja = {
  yell: function(n){
    return n > 0 ? yell(n-1) + "a" : "hiy";
  }
};


var samurai = { yell: ninja.yell };

ninja = {};

console.log(samurai.yell(2)); //hiy

      

http://ejohn.org/apps/learn/#14 (Original source, I modified it a bit to remove the named function expression).

+3


source to share


4 answers


In the following code:

var ninja = {
  yell: function(n){
    return n > 0 ? yell(n-1) + "a" : "hiy";
  }
};

      

The ninja.yell value is a function reference. Purpose:

var samurai = { yell: ninja.yell };

      

Assigns a value to samurai.yell, which is a reference to the same function (i.e., referenced by ninja.yell). Then:



ninja = {};

      

Assigns the value to ninja, which is a new, empty object. It does not affect the value assigned to samurai.yell, which still references the function.

Variables have a value, values ​​have a Type . There is a special type, Reference Type , which "... is used to explain the behavior of operators such as delete, typeof, and assignment operators." Therefore, when an object is in an expression, the assigned value is the Reference Type.

Hence, the variable still has a value, but that value is a reference.

+5


source


Break down the anonymous function referenced by the "yell" property for "ninja":

function yell(n) {
  return n > 0 ? yell(n-1) + "a" : "hiy";
}

var ninja = {
  yell: yell
};

      

Now it's a little easier to see that the "yell" function doesn't get "removed" when you reassign "ninja".



When you do:

var samurai = { yell: ninja.yell };

      

You assign any links to ninja.yell (what function yell()

} to "samurai.yell".

+1


source


It's important to look at the original unmodified source for this:

 1. | var ninja = { 
 2. |   yell: function(n){ 
 3. |     return n > 0 ? ninja.yell(n-1) + "a" : "hiy"; 
 4. |   } 
 5. | }; 
 6. | assert( ninja.yell(4) == "hiyaaaa", "A single object isn't too bad, either." ); 
 7. |  
 8. | var samurai = { yell: ninja.yell }; 
 9. | var ninja = null; 
10. |  
11. | try { 
12. |   samurai.yell(4); 
13. | } catch(e){ 
14. |   assert( false, "Uh, this isn't good! Where'd ninja.yell go?" ); 
15. | }

      

The change you made to change ninja.yell

to yell

is the wrong change to script.

I don't understand, when ninja object is set to empty object, yell method is still available for samurai.

It's important to understand how assignment works in JavaScript. JavaScript has many handy shorthand conventions that can be difficult to understand when you are new to the language.

var samurai = { yell: ninja.yell };

      

This is a shorthand way of saying:

var samurai;
samurai = new Object();
samurai.yell = ninja.yell;

      

When called samurai.yell = ninja.yell

, a function reference is ninja.yell

appended to samurai

.

In JavaScript, functions are also objects. They are transmitted by reference. What samurai.yell = ninja.yell

does not copy any link to ninja

.

Line 9 of the example does not change the function in any way . It also does not modify the object that has been saved in any way. What it does is remove the reference to the object that was stored in and replace it with the value . This means that any other copy of the referenced object will still point to the object the ninja was referring to. var ninja = null

ninja.yell

ninja

ninja

null

ninja

It's easier to see an example:

var foo,
    bar;

foo = {
    fizz: 'buzz'
};
bar = foo;
foo = null;
console.log(bar.fizz); //buzz

      

Is it because since there is still a link lying around the ninja, this is not garbage collection?

After running line 9 of the example script, there are no more references to the object that was in ninja

. There is a link to the function that was in ninja.yell

. This means that an object ninja

can be garbage collected, but an object ninja.yell

(which is a function) cannot.

0


source


Run execution in such a way that the JavaScript interpreter:

  • Create a new anonymous empty object (denoted as obj1

    ).
  • Create a new anonymous function named func1

    that does return n > 0 ? ...

    .
  • Add a new property of this object obj1

    called yell

    , which is an alias for the function func1

    .
  • Assign a reference to this object to a new property called root ninja

    (variables can be thought of as field properties).

At this point, the heap looks like this:

func1 = n => return n > 0 ? yell(n-1) + "a" : "hiy"
obj1  = { yell: func1 }
ninja = obj1

      

  1. Create a new anonymous empty object (denoted as obj2

    ).
  2. Add a new property to this object obj2

    called yell

    which is an alias for a function func1

    - not an alias for ninja.yell

    - the function reference "itself is copied into obj2.yell

    instead of a function reference.
  3. Assign obj2

    to samurai

    .
  4. Create a new anonymous empty object (denoted as obj3

    ).
  5. Assign a link to this object to ninja

    .

At this point, the heap looks like this:

func1   = n => return n > 0 ? yell(n-1) + "a" : "hiy"
obj1    = { yell: func1 } // this no-longer has any references and will be GC'd at some point
obj2    = { yell: func1 }
obj3    = {}
samurai = obj2
ninja   = obj3

      

  1. A call samurai.yell

    that will lead to dereferencing obj2

    and then func1

    to successfully complete the call.
0


source







All Articles