Notes of Maks Nemisj

Experiments with JavaScript

What you see is NOT what you get

Recently I’ve got a pleasure to debug some bug inside node.js app. Run-time was breaking with the following error:

copy.forEach( function(attrValue) {
     ^
TypeError: copy.forEach is not a function

Quite usual error, meaning that object has no forEach function. Let’s see the code itself:

function rebuild(data) {
  // for everything in the data we just fetched
  data.forEach( function(group) {
    // force array for attr
    if ( !Array.isArray(group.attr) ) {
      group.attr = [group.attr];
    }
    // for all values in attr
    const copy = group.attr.slice(0);
    copy.forEach( function(attrValue) {
    });
  });
}

I bet you were surprised like I was. This is just not possible from the first look, right?. If you read the code above, you can see that one of the developers have put a forcing of the array on member attr and Array MUST have forEach method. Which means JS executor is insane and doesn’t know what he is talking about. At least, this is what I was thinking in the first place.

After scratching my head, drinking a cup of coffee and setting debugger; statement exactly before the break, I understood that JS executor is not insane and I just can’t trust things I see. If you want to find out yourself, what caused the code to break, then don’t read next paragraph, but open your editor and try to reproduce the error. One small tip. You can reproduce it not only in node.js, but in any recent browser.

For those who are back, let’s see what was causing all this mess. It has appeared that attr member of group object was actually defined by using getter and setter. It was not just a plain object as I assumed at the begin, but it was a real instance of one class in this system. The setter on that instance was doing some magic to the passed value causing getter to return a simple value and not an Array.

{
    set attr(val) {
      this.attrValue = Array.isArray(val) ? val[0] : val;
    }
}

As I’ve already wrote in one of my article regarding getters and setters I still thinks it’s a bad idea. It might work in languages with static type checking, where every attribute has known type, but it is horribly broken in JavaScript, because JS developers are not used to fact that assign operator is doing some crazy stuff to the object.

, , ,

Leave a Reply

Your email address will not be published. Required fields are marked *