Rob Larsen

Things to know: JavaScript Objects are copied by reference not value

I was reading PPK's excellent JavaScript book during lunch and I came across a point in his chapter on Data Types (yes, I'm reading it straight through even if I already know all the basic bits) that I think a lot of people might not understand fully. As he says:

The object data type encompasses everything that's not a number, string, or boolean. It differs from the other three types because objects are copied, passed and compared by reference, not value.

Why is that important? What does that mean? Well, consider the following HTML fragment

<div id="fruit-loops-are-fun">
<p>Fruit Loops!</p>
</div>

and a function that evaluates the following statements

var fruit_loops_div = document.getElementById("fruit-loops-are-fun");
alert(fruit_loops_div.className);

the above returns an empty alert. Empty, of course, because there's no class name associated with that named div.

nothing.png

In the same function, consider now the the next two statements

document.getElementById("fruit-loops-are-fun").className="coco-pops";
alert(fruit_loops_div.className);

that pair returns this

class.png

So, the class is set with the className attribute and, note, when it's set the original reference is used and and not the assigned variable. Even still once the class is set, the variable immediately returns the correct value.

I thought about this for a minute and came up with an interesting illustration of how a lack of understanding of this concept could have catastrophic results. WARNING, this example snippet will lock your browser up, so don't run it :)

This is based on actual work I did for Compete, by the way. I built a Wordpress plugin for them that manipulated all the links on a page in several different ways based on user preferences. In its flashiest form it added some icons that fired a Snap-like* Ajax tooltip showing Compete Snapshot data for every URL on a blog page.

In this example, instead of manipulating the links in that way I've simplified it, deciding to simply add a link after each link on the page pointing to the Compete data for the referenced domain. This is easier to follow code-wise and this it allows me to show a potential pitfall of misunderstanding the topic at hand.

Here's the death code.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml">
  <head>
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
  <title>Endless Loop</title>
  <script type="text/javascript">
  window.onload= function(){
//get all the links
  var all_links = document.getElementsByTagName("a")
 //loop through them and append a compete link
     for (i=0; i<all_links.length;i++) {
          var new_a= document.createElement("a");
          new_a.setAttribute("href","http://siteanalytics.compete.com/"+all_links[i].href);
          var new_text=document.createTextNode("snap shot data for "+all_links[i].href);
          new_a.appendChild(new_text)
          insert_after(all_links[i].parentNode,new_a,all_links[i]);
      }
  }
  function insert_after(parent, node, referenceNode) 
  {
      parent.insertBefore(node, referenceNode.nextSibling);
  }
  </script>
  </head>
  <body>
  <p><a href="http://www.drunkenfist.com/">my one link</a></p>
  </body>
  </html>

Run the above code and your browser will die after being thrown into an infinite loop. That's because the all_links nodeList isn't some sort of static snapshot of document.getElementsByTagName("a") when it's first run (which a person unfamiliar with the concepts involved might assume.) It is document.getElementsByTagName("a") and that collection grows by one every time a new link is added. Therefore, i is never less than all_links.length and your browser instance will give up the ghost. You can see a variation here (I've set a static test, so it will end after < ∞ iterations) that shows the script running out of control.

So there's what not to do :) As a foil for this browser killing code (even if it is educational) I'll write up an example of how to safely do the above operation tomorrow.

[updated]as promised, a follow-up…[/updated]
*I was actually done, or close to done with this project when the Snap plugin was released, so we weren't copying their steez…

One Response to “ Things to know: JavaScript Objects are copied by reference not value ”

Leave a comment