Skip to content

Latest commit

 

History

History
1105 lines (811 loc) · 19.2 KB

JavaScript.md

File metadata and controls

1105 lines (811 loc) · 19.2 KB

magnetis();

Magnetis JavaScript code styleguide.

Table of contents

Disclaimer

This document is inspired by jQuery Style Guide, idiomatic.js and Airbnb JavaScript Style Guide.

⬆ back to top

Semicolons

  • Yes, please! ASI is very complicated, don't rely on it.
// Bad
(function() {
  var name = 'John'
  return name
})()

// Good
(function() {
  var name = 'John';
  return name;
})();

⬆ back to top

Strict mode

  • You should use the strict mode pragma. Just be aware not to use it globally!
// Bad
'use strict';

function doSomething() {
}

function doSomethingElse() {
}

// Good
function doSomething() {
  'use strict';
  // stuff
}

// Good
(function() {
  'use strict';

  function doSomething() {
  }

  function doSomethingElse() {
  }
})();

⬆ back to top

Context and closures

  • Always wrap your modules in closures creating a unique context of execution. Throwing things at the global scope can lead to all kinds of weird behaviors.
// Bad
function doAwesomeStuff() {
  $('.js-item').fadeIn();
}

function doEvenCoolerStuff() {
  $('.js-item').animate({top: 100}, 'fast');
}

// Good
(function($) {
  function doAwesomeStuff() {
    $('.js-item').fadeIn();
  }

  function doEvenCoolerStuff() {
    $('.js-item').animate({top: 100}, 'fast');
  }
})(jQuery);

// Good
var Module = (function() {
  function Module() {
    // magic happens here
  }

  return Module;
})();

⬆ back to top

Variables

Single var definition

  • Use single var definition approach when defining variables.
// Bad
var foo = 'Foo';
var bar = 'Bar';
var baz = 'Baz';

// Good
var foo = 'Foo',
  bar = 'Bar',
  baz = 'Baz';

Order

  • Variables with no startup value should come first.
// Bad
var name = 'John',
  surname = 'Doe',
  country,
  age = 42,
  email;

// Good
var country,
  email,
  name = 'John',
  surname = 'Doe',
  age = 42;

Style

  • Do not follow "comma first" style!
// Bad (OMG, really bad!)
var once
  , upon
  , aTime;

// Good
var once,
  upon,
  aTime;

// Bad
var user = {
  name: 'John',
  , surname: 'Doe'
  , age: 42
};

// Good
var user = {
  name: 'John',
  surname: 'Doe',
  age: 42
};

⬆ back to top

Objects

Object literal syntax

  • Use the literal syntax for object creation.
// Bad
var foo = new Object();

// Good
var bar = {};

Reserved words

  • Do not use reserved words as keys. They can cause problems in older IE versions.
// Bad
var foo = {
  class: 'Foo'
};

// Good
var bar = {
  klass: 'Bar'
};

// Good
var baz = {
  type: 'Baz'
};

Object keys

  • Use 🐫 camelCase when naming object keys when possible.
// Bad
var user = {
  'name': 'John',
  'has-children': false,
  'is-underage': false,
  'age': 42
};

// Good
var user = {
  name: 'John',
  hasChildren: false,
  isUnderage: false,
  age: 42
};
  • If you need to use quotes to wrap your keys for any reason, be consistent about it:
// Bad
var config = {
  development: true,
  'markdown-plugin': true,
  shouldIgnoreManifest: false,
  PersistData: true,
  enforcenamespace: true
};

// Good
var config = {
  'development': true,
  'markdown-plugin': true,
  'should-ignore-manifest': false,
  'persist-data': true,
  'enforce-namespace': true
};

// Good
var config = {
  development: true,
  markdownPlugin: true,
  shouldIgnoreManifest: false,
  persistData: true,
  enforceNamespace: true
};

⬆ back to top

Arrays

Array literal syntax

  • Use the literal syntax for array creation.
// Bad
var foo = new Array();

// Good
var bar = [1, 2, 3];

Adding items

  • If you don't know the array length use Array.push.
var groceries = [];

// Bad
groceries[groceries.length] = 'tomato';

// Good
groceries.push('oreo');

Cleaning up

  • To cleanup an array set its length to zero.
// Bad
var foo = [1, 3, 5];
foo = null;

// Good
var bar = [2, 4, 6];
bar.length = 0;

Array conversion

  • To convert an array-like object to an array, use Array.slice.
  • PS: you might want to do this because array-like objects (e.g {'0': 'hello', '1': 'there'} ) don't have methods like '.join()', for more information on this suject read this article
function argsToArray() {
  var args = Array.prototype.slice.call(arguments);
}

⬆ back to top

Strings

Quotes

  • Use single quotes '' for strings.
// Bad
var phil = "Philip Sampaio";

// Good
var luciano = 'Luciano Tavares';

String concatenation

  • Concat strings using the plus + operator.
var name = 'Rafael';

// Bad
name.concat('Rinaldi');

// Good
name += ' Rinaldi';

Long strings

  • Prefer string concatenation for long strings, always adding line breaks after an operator. Long strings can impact performance big time (benchmark and discussion).
// Bad
var errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';

// Bad
var errorMessage = 'This is a super long error that was thrown because \
of Batman. When you stop to think about how Batman had anything to do \
with this, you would get nowhere \
fast.';

// Good
var errorMessage = 'This is a super long error that was thrown because ' +
  'of Batman. When you stop to think about how Batman had anything to do ' +
  'with this, you would get nowhere fast.';

String conversion

  • To convert objects to string, use the toString() method.

  • The conversion with toString() does not work with null and undefined values. To convert any value to string, concats its value to an empty string. This is useful when you don't care about the value of the conversion (ex: in a logging or tracking system). In case you convert a null value, it will transform into "null". The same rule is applied to undefined values.

var value = 42;

// Good
value += '';

var empty;

empty += ''; // "undefined"

⬆ back to top

Functions

Function arguments

  • Whenever you have more than 3 arguments being passed to a function it's preferable to use an object instead.
// Bad

// Too many arguments
function setUser(firstName, lastName, age, gender, occupation) {
  // do stuff
}

setUser('Jon', 'Snow', 25, 'Male', 'Nights-watcher');

// Good

// Use a config/options object instead
function setUser(user) {
  // do stuff
}

setUser({
  firstName: 'Jon',
  lastName: 'Snow',
  age: 25,
  gender: 'Male',
  occupation: 'Nights-watcher'
});

Naming conventions

  • Use camelCase when naming objects, functions and instances.
// bad
var foo_bar = 'I am messed up';

// good
var fooBar = 'I am alright!';
  • Use PascalCase when naming constructors and "classes".
// Bad
function crewMember(name, role) {
  this.name = name;
  this.role = role;
}

var thales = new crewMember('Thales', 'Desenvolvedor');

// Good
function CrewMember(name, role) {
  this.name = name;
  this.role = role;
}

var vinicius = new CrewMember('Vinicius', 'Designer');

Naming functions

  • Avoid single letter names. Be descriptive and clear.
// Bad
function f() {
  // What the hell is this?
}

// Good
function bootstrapFoo() {
  // Ah, ok!
}

// Bad
function stuff() {
  // "stuff" is too generic
}

// Good
function doAnimationStuff() {
  // Now we're talking
}

Naming constructors

  • Always wrap constructor invocations with brackets. It's going to be easier to pass new constructor values if needed in the future.
// Bad
var foo = new FooBar;

// Good
var bar = new FooBar();
var baz = new FooBar(1, 'lorem');

Naming private properties

  • Always use a leading underscore _ when naming private properties and methods.
// Bad
var $name = 'Foo';
var __name = 'Bar';

// Good
var _name = 'Baz';

Referencing this

  • When making a reference to this name it as self.
// Bad
function() {
  var that = this;

  return function() {
    console.log(that);
  }
}

// Bad
function() {
  var _this = this;

  return function() {
    console.log(this);
  }
}

// Good
function() {
  var self = this;

  return function() {
    console.log(self);
  }
}

Naming booleans

  • When naming a Boolean variable, it should start with "is", "has", "should" or "was".
// Bad
var ready = true,
  animate = true,
  started = false,
  animation = true;

// Good
var isReady = true,
  shouldAnimate = true,
  wasStarted = true,
  hasAnimation = true;
  • When naming a Boolean function, it should start with "is".
// Bad
function ready() {
  return false;
}

// Good
function isReady() {
  return true;
}

Naming acessors

  • When naming an acessor, try to start with "get" or "set". Also explicitly name value as getters parameter.
var currentStatus;

// Bad
function status(val) {
  if (val) {
    currentStatus = val;
  }

  return currentStatus;
}

// Good
function setStatus(value) {
  currentStatus = value;
}

function getStatus() {
  return currentStatus;
}

Naming event handlers

  • When naming an event handler, combine its action with the event type.
// Bad
$('.button').click(click);

function click() {
  console.log('meh');
}

// Good
$('.button').click(toggleColorOnClick);

function toggleColorOnClick() {
  console.log('should toggle color on click!');
}

Naming element selectors

  • When naming class selectors of DOM elements that will have any kind of behavior, add js prefix to the name of your component separating words using an hyphen -.
<ul class="js-navigation-menu">
  <li>Foo</li>
  <li>Bar</li>
</ul>
var menu = $('.js-navigation-menu');

⬆ back to top

Properties

  • Use dot notation to access properties.
var user = {
  name: 'John',
  age: 42
};

// Bad
var userName = user['name'];

// Good
var userAge = user.age;
  • Use subscript notation [] to access dynamic properties.
var user = {
  name: 'John',
  age: 42
};

function getUserInfo(info) {
  return user[info];
}

var userName = getUserInfo('name');

⬆ back to top

Conditional Expressions and equality

  • Use === and !== over == and !=.

⬆ back to top

Blocks

  • Always wrap blocks within braces and embrace new lines.
// Bad
if (false)
  return;

// Bad
if (false) { return false; }

// Good
if (true) {
  return true;
}

// Good
if (true) {
  return true;
} else {
  return false;
}

⬆ back to top

Comments

  • Don't make trivial and obvious comments, be concise about it. If you caught yourself writing too much documentation for your code, consider a pair programming because you're likely over engineering it.

  • Feel free to use markdown syntax on code comments.

  • No need to use JSDoc syntax since we don't automatically generate documentation.

  • Using FIXME, TODO and NOTE tags can help other developers understand and maintain your code. You can use it as you want.

  • Use documentation block syntax followed by a newline for multiline comments. There are tools available to make it really easy.

// Bad

// Used to match `RegExp` special characters.
// See this [article on `RegExp` characters](http://www.regular-expressions.info/characters.html#special)
// for more details.

var matchSpecialChars = /[.*+?^${}()|[\]\/\\]/g;

// Bad

/*
Used to match `RegExp` special characters.
See this [article on `RegExp` characters](http://www.regular-expressions.info/characters.html#special)
for more details.
*/

var matchSpecialChars = /[.*+?^${}()|[\]\/\\]/g;

// Good

/**
* Used to match `RegExp` special characters.
* See this [article on `RegExp` characters](http://www.regular-expressions.info/characters.html#special)
* for more details.
*/

var matchSpecialChars = /[.*+?^${}()|[\]\/\\]/g;
  • Use // for single line comments. Place single line comments on a newline above the subject of the comment and add an empty line before the comment.
// Bad
var active = true;  // is current tab

// Good
// is current tab
var active = true;

// Bad
function getType() {
  console.log('fetching type...');
  // set the default type to 'no type'
  var type = this._type || 'no type';

  return type;
}

// Good
function getType() {
  console.log('fetching type...');

  // set the default type to 'no type'
  var type = this._type || 'no type';

  return type;
}

⬆ back to top

Whitespace

Tabs

  • Use soft tabs set to 2 spaces and never mix spaces with tabs.
// Bad
function() {
∙∙∙∙var name;
}

// Bad
function() {
∙var name;
}

// Bad
function() {
⇥var name;
}

// Good
function() {
∙∙var name;
}

EOF

  • Always add an empty line at the end of your file.
// Bad
(function() {
  document.write('Hello World!');
})();

// Good
(function() {
  document.write('Hello World!');
})();

Condition and loop declarations

  • Place 1 space before and after a condition or loop declarations.
// Bad
if(false){return false;}

// Good
if (true) {
  return true;
}

// Bad
while(false){console.log('whatever');}

// Good
while (false) {
  console.log('alright!');
}

Operators

  • Set off operators with spaces.
// Bad
var x=y+5;

// Good
var x = y + 5;

Loop steps

  • Place 1 space after loop steps and function arguments.
// Bad
for(var i=0;i<10;++i) {
  console.log(i);
}

// Good
for (var i = 0; i < 42; ++i) {
  console.log(i);
}

// Bad
function setUser(name,surname,age){
  // sets user
}

// Good
function setUser(name, surname, age) {
  // sets user
}

Object declarations

  • In objects that have more than a single property you should break all properties into new lines.
// Bad
var user = {name: 'John', surname: 'Doe', age: 42};

// Good
var user = {
  name: 'John',
  surname: 'Doe',
  age: 42
};
  • Add inner spaces when declaring inline objects.
// Bad
var app = {locale: 'pt-br'};

// Good
var app = { locale: 'pt-br' };

Chaining

  • Use indentation when making long method chains.
// Bad
$('#items').find('.selected').highlight().end().find('.open').updateCount();

// Good
$('#items')
  .find('.selected')
    .highlight()
    .end()
  .find('.open')
    .updateCount();

⬆ back to top

Type checking

String

typeof variable === 'string';

Number

typeof variable === 'number';

Boolean

typeof variable === 'boolean';

Object

typeof variable === 'object';

Array

Array.isArray(arrayLikeObject);

Node

elem.nodeType === 1;

null

variable === null;

null or undefined

variable == null;

undefined

Global variables

typeof variable === 'undefined';

Local variables

variable === undefined;

Property

object.prop === undefined;
object.hasOwnProperty(prop);
'prop' in object;

⬆ back to top

Best practices

  • Do not start closures with semi-colons.

  • We encourage you to log important app events and changes in development mode only. Follow the format of Module/ClassName :: method() :: message.

function App() {
  console.log('App :: App instance created');
}

App.prototype.bootstrap = function() {
  console.log('App :: bootstrap() :: App was initialized');
};

jQuery

  • Cache jQuery lookups always when possible.
  • Prefer remove() over empty().
  • Always favor functional and utility functions of jQuery over Underscore.

⬆ back to top

Links

Articles and blog posts

Tools

⬅ back to main    ⬆ back to top