Codeschool JavaScript Best Practices Notes

I finished the course at CodeSchool, and below are my notes from it.

Level 1

Ternary howto with SIAF

var allPacked = true;
var readyToGo = true;
var adventureTime;

adventureTime = allPacked && readyToGo ?

  function( ){
    return "Adventure time is now!" ;
  }()
  :
  function( ){
    return "Adventuring has been postponed!" ;
  }() ;

console.log(adventureTime);

Short-circuting, if the this.swords is not empty it takes it immediately, without looking at the thing after the ||

this.swords = this.swords || [];

Same goes for &&, as soon as it finds a first falsy value – it returns that. If all falsy, it returns the last one.

Level 2

If you need lengthy, repetitive access to a value nested deep within a JS Object, then cache the necessary value in a local variable.

var numCritters = location.critters.length;
for(var i = 0; i < numCritters; i++){
      list += location.critters[i];
}

//instead of
for(var i = 0; i < location.critters.length; i++){
      list += location.critters[i];
}

//and even better
for(var i = 0, numCritters = location.critters.length; i < numCritters; i++){
    list += location.critters[i];
}

Put script tag just before the ending body tag, or you can also leave them in the head section, but add async keyword. Use a list of variables after the keyword var all at once! Use function join() on the array instead of concatenation. with +=. console.time(“string”) is the opening statement to a timer method that will help us measure how long our code is taking to perform. console.timeEnd(“string”) ends it and prints how long it took. “string” has to be the same in both cases.

var now = new Date();

console.log(+now) == console.log(new Number(now));

 Level 3

 === compares type and content. instanceof – userful to determine, well, the instance of some object 🙂

function Bird(){}
function DatatypeBird(){}
function SyntaxBird(){}
DatatypeBird.prototype = Object.create(Bird.prototype);
SyntaxBird.prototype   = Object.create(Bird.prototype);

Runtime error catching:

try{
   if(someVar === undefined)
        throw new ReferenceError();
}
catch(err){
    if(err instanceof ReferenceError)
        console.log("Ref err:" + err);

    //TypeError
}
finally{
    //this will execute no matter what
}

Avoid eval, with.

Use num.toFixed(2), parseFloat(), parseInt(num, radix). Radix can be from 2 – 36. typeof along with isNan to determine if the number is trully a number.

Level 4

Namespace is an object that groups and protects related data and methods in JavaScript files.

Say you have a code like this:

var treasureChests = 3;
var openChest = function(){
    treasureChests--;
    alert("DA DADADA DAAAAAAA!");
};

you can use namespacing like this:

var DATA = {
	treasureChests : 3,
	openChest : function(){
	    this.treasureChests--;
	    alert("DA DADADA DAAAAAAA!");
	}
};

You then call the function like this: DATA.openChests().

Closures are a feature of JavaScript, used to cause some properties to be private, bound only to a surrounding function’s local scope, and some properties to be public, accessible by all holders of the namespace.

Private properties are created in the local scope of the function expression. Public properties are built within the object which is then returned to become the namespace. Access to private data is thus possible only because of closure within the larger module.

Say you have a code like this:

var CAVESOFCLARITY = {
  stalactites: 4235,
  stalagmites: 3924,
  bats: 345,
  SECRET: {
    treasureChests: 3,
    openChest: function(){
      this.treasureChests--;
      alert("DA DADADA DAAAAAAA!");
    }
  }
};

You would make it into a closure like this:

var CAVESOFCLARITY = function () {

  var treasureChests = 3;

  return {
    stalactites: 4235,
    stalagmites: 3924,
    bats: 345,
    openChest: function () {
        treasureChests--;
        alert("DA DADADA DAAAAAAA!");
    }
  };
}();

If a module references globally-scoped variables, it’s a best practice to bring them into the scope of anonymous closure through the use of a specific technique called global imports.

Say the code is like this and uses a global variable named globalAnswer:

var MySomething = function () {
  var a = 3;

  return {
    getA: function() {return a; },
    summon: function(){
      if(globalAnswer === "42"){
        alert("YEP!");
      }
      else{
          alert("NOPE");
      }
    }
  };
}();

You would rewrite this using global imports like this:

var MySomething = function (answer) {
  var a = 3;

  return {
    getA: function() {return a; },
    summon: function(){
      if(answer === "42"){
        alert("YEP!");
      }
      else{
          alert("NOPE");
      }
    }
  };
}(globalAnswer);

Your import ensures clarity of scope within a module. By using a parameter, you protect the global data that might have been overwritten. All imported data becomes locally scoped to the anonymous function, to be used in closure. Thus, when compared with searching the entire scope, import are both clearer and faster.

Augmentation is the term for adding or changing properties in a module after the module has already been built.

In simple augmentation, the module file and the augmentation file do not share their private state. Augmented module properties may only access the private data from their file’s closure. Private data from the original closure will not be lost, and will be accessible to all original properties that referenced it.

Written by Nikola Brežnjak