Common mistakes made by new Javascript developers (even/especially experienced programmers)

Inheritance and this

You can’t really discuss this without talking about call() and apply(). this is just the scope you currently are operating within. But sometime you need to call a method from another scope (object) and apply it to the one you are working in, or the method you are working with needs to be applied to another scope. This becomes a necessity with callbacks.

This subject also takes care of inheritance in Javascript and the prototype inherent to it. After a couple of functions that don’t really have any bearing on the real world, we create our Mammal class and then show how Lion and Kangaroo inherit from them. The call method is used, and you can’t really talk about call without talking about apply. The only real difference is the way you pass parameters in each method.

method.call

method.call(object, arg1, arg2, arg3);

method.apply

method.apply(object, [arg1, arg2, arg3]);

With apply you are passing all your parameters in one array-like list, arguments. It’s a little difference but easier to iterate over on the receiving end, but we need to talk a little bit more about arguments, which we will after the code.

function getTerrainEffect(type){
  if(type=='undefined') return;
  var effect;
  if(type=='Lion'){
    switch(terrain){
      case 'rocks':
        effect = 5;
      break;
      case 'sand':
        effect = 3;
      break;
      case 'water':
        effect = 9;
      break;
      default:
        effect = 0;
    }
  } else if(type=='Kangaroo'){
    switch(terrain){
      case 'rocks':
        effect = 6;
      break;
      case 'sand':
        effect = 2;
      break;
      case 'water':
        effect = 9;
      break;
      default:
        effect = 0;
    }
  }
  return effect; 
}

function actualSpeed(effect, maxSpeed){ 
  return (maxSpeed - maxSpeed*effect/10);
}

function Mammal(){ }
Mammal.prototype.type     = null;
Mammal.prototype.effect   = getTerrainEffect();
  
function Lion(){
  Mammal.call(this);
}
// inherit Mammal
Lion.prototype = new Mammal();

// correct the constructor pointer because it points to Mammal
Lion.prototype.constructor = Lion;
Lion.prototype.legs        = 4;
Lion.prototype.type        = "Lion";
  
function Kangaroo(){
  Mammal.call(this);
}
Kangaroo.prototype             = new Mammal();
Kangaroo.prototype.constructor = Kangaroo;
Kangaroo.prototype.legs        = 2;
Kangaroo.prototype.type        = "Kangaroo";

arguments

Check out arguments on MDN for all the details, but here is the summary. arguments is not a real Array, so it doesn’t contain all the methods in the Array prototype. You can convert it into an array simply by calling

var args = Array.prototype.slice.call(arguments);

in the beginning of your function, though there is a cost to optimizations in Chrome’s V8 engine, for example. If Array generics are available, one can use the following instead:

var args = Array.slice(arguments);

Block-level scope

for (var i = 0; i < 10; i++) {
  /* ... */
}
console.log(i);  // what will this output?

No, not undefined, nor will it throw an error. It will output 10. i still lives outside of the for-block.

Boolean Equality

One of the conveniences in JavaScript is that it will automatically coerce any value being referenced in a boolean context to a boolean value. But this can be very confusing to developers from other languages who don't know the details of this type-coercion.

// All of these evaluate to 'true'!
console.log(false == '0');
console.log(null == undefined);
console.log(" \t\r\n" == 0);
console.log('' == 0);

// And these do too!
if ({}) // ...
if ([]) // ...

Accordingly, unless type coercion is explicitly desired, it’s typically best to use === and !== (rather than == and !=), so as to avoid any unintended side-effects of type coercion. (== and != automatically perform type conversion when comparing two things, whereas === and !== do the same comparison without type conversion.)

Inefficient DOM Manipulation

Adding DOM elements individually is an expensive operation, and unfortunately a very common one. Instead ECMA has come up with an alternative to the whole document, a fragment which is basically an empty document. Manipulation of this fragment is much less costly and results in more efficient code. Consider the code below and then read up on DocumentFragment.

var div = document.getElementsByTagName("my_div");

var fragment = document.createDocumentFragment();

for (var e = 0; e < elems.length; e++) {  // elems previously set to list of elements
    fragment.appendChild(elems[e]);
}
div.appendChild(fragment.cloneNode(true));

The for...in loop

I think this is what initiated this request from Carl. Though it seems very efficient and a nice way to iterate through objects, it should strictly be used to iterate through objects. While an array is technically an object it uses numeric indexes where the order is important as shown by the pop, push, and reverse methods. Objects don't care too much about the order of their properties and neither does the for...in loop. Use the for-loop or forEach for arrays.