This is meant to be the beginning guidelines for JavaScript code at SolutionStream. This guide represents our ES5 standards.We are aligning ourselves closely with the styleguides produced by Google (https://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml) and Airbnb (https://github.com/airbnb/javascript/tree/master/es5)
##Table of Contents
- Coding Principles
- Styles
- Variables
- Objects
- Arrays
- Functions
- Properties
- Comparison Operators & Equality
- Blocks
- Whitespace
- Method Chaining
- Readability
- KISS - Keep it simple
//bad var luhnChk = (function (arr) { return function (ccNum) { var len = ccNum.length, bit = 1, sum = 0, val; while (len) { val = parseInt(ccNum.charAt(--len), 10); sum += (bit ^= 1) ? arr[val] : val; } return sum && sum % 10 === 0; };
}([0, 2, 4, 6, 8, 1, 3, 5, 7, 9]));
* Descriptive Code
* Use descriptive functions and variable names
```JavaScript
//bad
var nm = 'Person Name';
function process() {}
function myFunction() {}
angular.module('myApp', []);
//good
var patientName = 'Person Name';
function processPatient() {}
function login() {}
angular.module('',[])
```
* Avoid contractions
* Maintainability
* 'use strict'
* Without strict mode, assigning a value to an undeclared variable creates a global variable which can clobber
other global variables. Strict mode throws an error and does not allow values to be assigned to undeclared
variables.
* Without strict mode, a reference to a this value of null or undefined is automatically coerced to the global.
In strict mode, this causes an error.
* SRP - Single responsibility principle
* NPM and Bower support
* Use lodash
* Testing
* Build Process
* Modularity
* DRY - Don't repeat yourself
* Leverage modules properly
* Group code into related bundles. This way if you remove a module, your app still works.
* app.controllers, app.services, etc will break your app if you remove them
* app.users, app.users.edit, app.users.admin, app.projects, etc allows you to group and nest related components together and create loose coupling
* Angular - spread route definitions across multiple .config() methods
* Folder structure should reflect module structure
* Performance
## Styles
JSCS - JavaScript Code Style
* http://jscs.info/
* I want to start using the Google preset with the caveat of max line length of 120
* Can be run from the command line with the option to fix current JavaScript, not just lint
Naming
* Functions, Variables, Methods
* Use Camel Case
* functionNamesLikeThis
* variableNamesLikeThis
* methodNamesLikeThis
* Classes, Angular Controllers
* Pascal Case
* ClassNamesLikeThis
* ControllerNamesLikeThis
* Descriptive Suffix
* HomeController
* TabDirective
* AuthenticationService
* Constants
* All upper
* CONSTANT_VALUES_LIKE_THIS
Strings
* Use single quotes for strings
Indentation
* Tabs as spaces
* 2 spaces for each indentation
Commenting
* In general, the code should be readable with little to no commenting nescessary
* Avoid comments like that state the obvious
```JavaScript
var apple = new Apple(); // initing the apple - NO!
##Variables
- Always declare with var
- When you fail to specify var, the variable gets placed in the global context and can potentially clobber existing values
- Declare one variable per var statement, it makes it easier to re-order the lines.
//right
var keys = ['foo', 'bar'];
var values = [23, 42];
var object = {};
while (keys.length) {
var key = keys.pop();
object[key] = values.pop();
}
//wrong
var keys = ['foo', 'bar'],
values = [23, 42],
object = {},
key;
while (keys.length) {
key = keys.pop();
object[key] = values.pop();
}
##Objects
- Use the literal syntax for object creation
//bad
var item = new Object();
//good
var item = {};
- Don't use reserved words as keys. It won't work in strict mode
//bad
var batman = {
default: {
name: 'Bruce Wayne'
},
private: true
}
//good
var batman = {
defaults: {
name: 'Bruce Wayne'
},
hidden: true
}
- Use readable synonyms in place of reserved words
//bad
var superman = {
class: 'alien'
}
//bad
var superman = {
klass: 'alien
}
//good
var superman = {
type: alien
}
##Arrays
- Use the literal syntax for array creation
//bad
var items = new Array()
//good
var items = [];
- Use array#push instead of a direct assignment
var someStack = [];
//bad
someStack[someStack.length] = 'value';
//good
someStack.push('value');
##Functions
- Keep your functions short. A good function fits on a slide that the people in the last row of a big room can comfortably read. So don't count on them having perfect vision and limit yourself to ~15 lines of code per function.
- Feel free to give your closures a name. It shows that you care about them, and will produce better stack traces, heap and cpu profiles.
//right
req.on('end', function onEnd() {
console.log('winning');
});
//wrong
req.on('end', function() {
console.log('losing');
});
- Ternary is fine when it serves a simple purpose
var valid = (object && object.value) ? true : false
- Avoid ternary when using function operators and complex comparisons
//bad
var valid = (checkObject(object) && checkObjectValue(object) === true) ? true : false;
//better
var valid = false;
if (checkObject(object) && checkObjectVAlue(object) === true) {
valid = true;
}
- Avoid code inception at all costs
- Makes reading/debugging the code super difficult
- This includes closures within closures
- Also includes jQuery this, this, this
##Properties
- Use dot notation when accessing properties
var luke = {
jedi: true,
age: 28
};
//bad
var isJedi = luke['jedi'];
//good
var isJedi = luke.jedi;
- Use subscript notation
[]
when accessing properties with a variable
var luke = {
jedi: true,
age: 28
};
function getProp(prop) {
return luke[prop];
}
var isJedi = getProp('jedi');
##Comparison Operators & Equality
- Use === and !== over == and !=
- Use shortcuts.
//bad
if (name !== '') {
//stuff
}
//good
if (name) {
//stuff
}
//bad
if (collection.length > 0) {
//stuff
}
//good
if (collection.length) {
//stuff
}
- Use descriptive conditions
//right
var isValidPassword = password.length >= 4 && /^(?=.*\d).{4,}$/.test(password);
if (isValidPassword) {
console.log('winning');
}
//wrong
if (password.length >= 4 && /^(?=.*\d).{4,}$/.test(password)) {
console.log('losing');
}
##Blocks
- Use braces with all if statements
//bad
if (false === true) login();
//good
if (false === true) {
login();
}
##Whitespace
- Following JavaScript Code Style - Google Preset
- Use tabs as spaces set to 2 spaces
- Place 1 space before each leading brace
//bad
if (false === true){
}
//good
if (false === true) {
}
//bad
function login(){
}
//good
function login() {
}
- Place 1 space before the opening parenthesis in control statements (if, while, etc). Place no space before the argument list in function calls and declarations
//bad
if(false === true) {
}
//good
if (false === true) {
}
//bad
while(false === true) {
}
//good
while (false === true) {
}
##Method Chaining
- One method per line should be used if you want to chain methods
- You should also indent these methods so it's easier to tell they are part of the same chain
//right
User
.findOne({ name: 'foo' })
.populate('bar')
.exec(function(err, user) {
return true;
});
//wrong
User
.findOne({ name: 'foo' })
.populate('bar')
.exec(function(err, user) {
return true;
});
User.findOne({ name: 'foo' })
.populate('bar')
.exec(function(err, user) {
return true;
});
User.findOne({ name: 'foo' }).populate('bar')
.exec(function(err, user) {
return true;
});
User.findOne({ name: 'foo' }).populate('bar')
.exec(function(err, user) {
return true;
});