Skip to content

Instantly share code, notes, and snippets.

@danprince
Last active August 29, 2015 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danprince/92b5e5332a51c08a5b82 to your computer and use it in GitHub Desktop.
Save danprince/92b5e5332a51c08a5b82 to your computer and use it in GitHub Desktop.
Javascript Guide

Dan's Guide to Javascript (Working Progress)

###Two Space Indents Do not use tab characters. All indents should be two spaces wide and the tab key should be set to insert soft tabs in your editor.

function action(intent) {
  function compile(element, listeners) {
    if(intent) {
      element.addEventListener('click', listeners.click);
    }
  }
  return compile;
}

###Egyptian Style Braces They look nicer, the help condense your code without making it feel stringy.

if(ship.isFlying) {
  ship.update();
} else if(ship.hasCrashed) {
  player.score--;
} else {
  ship.fuel++;
}

###Declare variables at the top of functions Javascript doesn't have block level scoping. It's easy to forget this, so to ensure that it doesn't trip you up, declare all variables at the top of the functions they are used in.

var multiplexer, stream, byte;
multiplexer = new FQMMultiplexer();
while(byte = stream.read()) {
  multiplexer.combine(byte);
}

###CommonJS CommonJS rocks. Modularity is 100% a good thing. It'll be a while before ES6 has full coverage, but for now, we can use CommonJS to make our code better.

###Hoist those Functions! Declare named functions where possible and reasonable to make the important blocks of code in your application more accessible and readable.

###Use commas in multiple declarations Declaring lots of variables? You don't need lots of var keywords.

var danger, warning, success, event;

Alternatively, if they all have values, initialize them there

var danger = 0,
  warning = 1,
  success = 2,
  event = 3;

###Pad for Clarity Use spaces to make the following clearer. Arithmetic

var a = (1 + 9) - (6 * 8) / (3 * 5);

Logic

(hidden && crouching) || (!hidden && standing)

Parameters

function test(a, b, c) { ... }
test(1, 2, 3);

###No multiline comments Regular expressions tend to break multiline comments.

###Prefer promises to callbacks Asynchronous programming is difficult. Callback soup makes it harder. Whenever you are writing an API, prefer Promises (Q) to callbacks.

deferred.reject should only be called in case of an error.

Like everything else, promises should be defined at the top of the function from which they are returned.

function once(event) {
  var deferred, delegate;
  
  deferred = Q.defer();
  delegate = false;
  if(event.which === 13) {
    deferred.resolve();
  } else {
    deferred.reject();
  }

  return deferred.promise;
}

###Use array/object literals Prefer use of [] over new Array() and {} over new Object().
Their behaviour is more reasonable, and they are syntactically concise, without losing meaning.

###Use null in space of objects Whenever you are working with a variable that will later be instantiated as an object, set its value to null. This helps other programmers know that what was returned was the absence of an object, rather than there necessarily being an error.

function siginin(state) {
  var account, token;
  account = null;
  if(token = state.getAuth()) {
    account = server.provideToken(token);
  }
  return account;
}

if(signin(globalState) === null)) {
  throw new Error('Authentication failed');
}

###Chain on new lines Sometimes chaining statements is a good thing. When this is the case, always chain onto a new line.

var words = input()
.toLowerCase()
.replace('"', '\'')
.split(' ')
.filter(function(word) {
  return length > 3;
});

Because let's be honest, that looks a million times better than the alternative:

var words = input().toLowerCase().replace('"', '\'').split(' ').filter(function(word) {
  return length > 3;
});

###Always use braces for if statements It will make everyone's lives less confusing if you stick to a good convention of using curly braces for all block statements.

if(telling.the('truth'))
  money++;
else
  money--;
  fame--;

The indent tricks readers into thinking that fame will be decremented as part of the else block. Egyptian style braces only add one extra line to this construct. Do it for everyone's sake.

if(err) throw err; is acceptable.

#####Sidenote: It is sometimes ok to use the ternary operator.

curried.bind(this, arity < 3 ? lowFn : highFn);

Compared to the verbose version, the above is arguably more elegant.

var bound;
if(arity < 3) {
  bound = lowFn;
} else {
  bound = highFn;
}
curried.bind(this, bound);

###Use semantic conditions (prop in obj, obj instanceof Class) Where possible, use the in and instanceof keywords to make your code more readable.

lottery.winners = {
  steve: 1,
  peter: 3,
  jim: 1,
  frank: 2
}

if(player.name in lottery.winners) {
  console.log('You won!');
}
if(events instanceof Array) {
  
}

Pitfall: _It is important to bear in mind that if you want to negate these kind of inline keyword expressions, you have to wrap the entire statement in parentheses, before negating them, otherwise your negation will apply to the first term only.

if(!events instanceof Array) {
  // events == []
  // !events == false
  // false instanceof Array == false
}

###Use camelCase The standard library's convention is camelcase, if you use anything else, you will confuse and annoy people.

###Know how deep is too deep Nesting blocks is ok, but know when you have gone too deep into a nested structure. When you do, attempt to remove some of the structure and build it into another construct.

var tickets = TicketVendor.distribute();
tickets.forEach(function(ticket) {
  if(ticket) {
    ticket.validate(Date.now());
    if(ticket.validated) {
      ticket.sign({
        clerk: {
          name: "Harry Balding",
          date: ticket.validated
        },
        vendor: {
          name: TicketVendor.name
        }
      });
      ticket.process(function(err, certificate) {
        if(err) {
          throw err;
        } else {
          certificate.grant(ticket);
        }
      });
    } else {
      TicketVendor.discard(ticket);
    }
  }
});

Yep, horrible.

TicketVendor.distribute().forEach(checkTicket);

function checkTicket(ticket) {
  if(ticket) {
    validateTicket(ticket);
  }
}

function validateTicket(ticket) {
  ticket.validate(Date.now());
  if(ticket.validate) {
    signTicket(ticket);
    processTicket(ticket);
  } else {
    TicketVendor.discard(ticket);
  }
}

function signTicket(ticket) {
  ticket.sign({
    clerk: {
      name: "Harry Balding",
      date: ticket.validated
    },
    vendor: {
      name: TicketVendor.name
    }
  })
}

function processTicket(ticket) {
  ticket.process(function(err, certificate) {
    if(err) throw err;
    certificate.grant(ticket);
  });
}

###Don't use inline js Inline JS is confusing, unexpected and harder to debug. Don't do it.

###Don't use eval If you run eval on user input, expect a world of pain.

###Don't use new Function Same as above.

###Don't use with With is notoriously slow and makes it difficult to make proper reasoning about blocks of code.

###Don't use labels They aren't that useful and next to no one knows that Javascript has them. Don't use them.

###Don't go beyond 80 characters Some people still use terminals, break your lines before they get to 80 characters.

###Don't use for in It's very easy to end up with extra properties on an object. Unless they were explicitly declared so that they couldn't be iterated over, then for-in will get them.

###Use map, reduce, filter, forEach (ES5 shim) Code becomes more elegant with these 4. They aren't supported in some browsers, so make sure you always supply the ES5 shim alongside.

Node

Angular

Inject Angular services first

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment