Skip to content

greenpioneersolutions/gps-style-guide

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 

Repository files navigation

JavaScript Style Guide - JavaScript Standard Style
GPS Style Guide - RENAME TO GUIDE

Green Pioneer Solutions Style Guide to all things we develop


GitHub version

Table of Contents

Intro

Welcome to all of those who are here reading this. This is the Green Pioneer Solutions style guide to code. We will be write about many bigger than just code and syntax. We will use this guide to help you in any way possible. For example were going to take a dive into other things that make us successful than just style like blogs, mentors, other style guides, mistakes and tools. Thats just to name a few.

Why: We are building this guide to help you figure

How: we plan to accomplish this by write how style our code and showing you lots

What: you will have a guide to come follow to help you along your journey as a developer

This guide is not a one size fits all. the goal

Approach

Maybe talk about my approach

Installs

Installs

Style

Javascript Style

Description of the JS

SubPoint

Description of the section

// Style

Control Flow

Description of the section

// Style

Lodash

Description of the section

// Style

Be Async

Description of the section

// Style

When to Be Sync

Description of the section

// Style

Promises

Description of the section

// Style

Bind Call Apply

Description of the section

// Style

Avoid polluting the global scope

Declaring variables is a lot of fun. Sometimes, you may declare global variables even if you don't want to. In today's browsers, the global variables are stored in the window object. So, since there's a lot of stuff going on there, you may override default values.

Let's suppose you have an HTML file which contains a <script> tag containing (or which loads a JavaScript file containing):

var foo = 42;
console.log(foo);

This will obviously output 42 in the console. But since the code is not executed in a function, the context will be the global one. So, the variables are attached to the window object. This means that window.foo is 42 as well.

This is dangerous since you can override existing global variables:

function print () {
   // do something
}
print();

When executing window.print (or just print), it won't open the print popup since we have overriden the native print popup.

The solution is quite simple; we need a wrapping function that is called immediately, like below:

// Declare an anonymous function
(function () {
   var foo = 42;
   console.log(window.foo);
   // → undefined
   console.log(foo);
   // → 42
})();
//^ and call it immediately

Alternatively, you could choose to send the window and other globals (e.g. document) as arguments to that function (this will probably improve the performance):

(function (global, doc) {
  global.setTimeout(function () {
     doc.body.innerHTML = "Hello!";
  }, 1000);
})(window, document);

So, do use the wrapping function to prevent creating globals. Note that I'm not going to use the wrapping function in the code snippets below since we want to focus on the code itself.

💡 Tip: browserify is another way to prevent creating globals. It uses the require function the same way you do it in Node.js.

By the way, Node.js does wrap your files in functions automatically. They look like this:

(function (exports, require, module, __filename, __dirname) {
// ...

So if you thought the require function is a global one, well, it's not. It's nothing more than a function argument.

Did you know? Since the window object contains the global variables and since it is a global itself, the window references itself inside:

window.window.window
// => Window {...}

That's because the window object is a circular object. Here's how to create such an object:

// Create an object
var foo = {};

// Point a key value to the object itself
foo.bar = foo;

// The `foo` object just became a circular one:
foo.bar.bar.bar.bar
// → foo

Use Strict

Strictly use use strict! This is nothing more than just adding string put in your code that adds more magic to your script.

  // This is bad, since you do create a global without having anyone to tell you
  (function () {
     a = 42;
     console.log(a);
     // → 42
  })();
  console.log(a);
  // → 42

Using use strict, you can get quite a few more errors:

  (function () {
     "use strict";
     a = 42;
     // Error: Uncaught ReferenceError: a is not defined
  })();

You could be wondering why you can't put the use strict outside of the wrapping function. Well, you can, but it will be applied globally. That's still not bad; but it will affect it if you have code which comes from other libraries, or if you bundle everything in one file.

Strict equal

This is short. If you compare a with b using == (like in other programming languages), in JavaScript you may find this works in a weird way: if you have a string and a number, they will be equal (==):

"42" == 42
// → true

For obvious reasons (e.g. validations), it's better to use strict equal (===):

"42" === 42
// → false

|| and &&

Depending on what you need to do, you can make your code shorter using logic operators.

Defaults

"" || "foo"
// → "foo"

undefined || 42
// → 42

// Note that if you want to handle 0 there, you need
// to check if a number was provided:
var a = 0;
a || 42
// → 42

// This is a ternary operator—works like an inline if-else statement
var b = typeof a === "number" ? a : 42;
// → 0

Instead of checking if something is truly using an if expression, you can simply do:

expr && doSomething();

// Instead of:
if (expr) {
   doSomething();
}

That's even fancier if you need the result returned by doSomething():

function doSomething () {
   return { foo: "bar" };
}
var expr = true;
var res = expr && doSomething();
res && console.log(res);
// → { foo: "bar" }

You may not agree with me here, but this is more ideal. If you don't want to uglify your code this way, this is what these JavaScript minifiers will actually do.

If you ask me, though the code is shorter, it is still human-readable.

Convert value types

There are several ways to convert these things depending on how you want to do it. The most common ways are:

// From anything to a number

var foo = "42";
var myNumber = +foo; // shortcut for Number(foo)
// → 42

// Tip: you can convert it directly into a negative number
var negativeFoo = -foo; // or -Number(foo)
// → -42

// From object to array
// Tip: `arguments` is an object and in general you want to use it as array
var args = { 0: "foo", 1: "bar", length: 2 };
Array.prototype.slice.call(args)
// → [ 'foo', 'bar' ]

// Anything to boolean
/// Non non p is a boolean p
var t = 1;
var f = 0;
!!t
// → true
!!f
// → false

/// And non-p is a boolean non-p
!t
// → false
!f
// → true

// Anything to string
var foo = 42;
"" + foo // shortcut for String(foo)
// → "42"

foo = { hello: "world" };
JSON.stringify(foo);
// → '{ "hello":"world" }'

JSON.stringify(foo, null, 4); // beautify the things
// →
// '{
//    "hello": "world"
// }'

// Note you cannot JSON.stringify circular structures
JSON.stringify(window);
// ⚠ TypeError: JSON.stringify cannot serialize cyclic structures.

Variable declarations

Variables

Using var in general or let when they should be accesible only in specific blocks (e.g. if).

// One declaration
var foo = 1;

// Multiple declarations
var foo = 1
  , bar = "Hello World"
  , anotherOne = [{ foo: "bar" }]
  ;

if (...) {
   let baz = 42;
  /* do something with baz */
}
Constants

Using const. The constant names are written with UPPERCASE letters. I also use const when including libraries using require and when they should not be changed. In this case, the names will not be with caps.

// Dependencies
const http = require("http")
   , fs = require("fs")
   , EventEmitter = require("events").EventEmitter
// Constants
const PI = Math.PI
    , MY_CONSTANT = 42
    ;
Globals

I define globals when there is no commonjs environment (this is actually handled by dist-it. When I manually define globals, I do that using window.MyGlobal (on the client) and global.MyGlobal (on the server).

Iterating object and arrays

For arrays, most of times, I use the forEach function:

arr.forEach(c => {
    // do something
});

However, using for loops is fine too:

for (var i = 0; i < arr.length; ++i) {
    for (var ii = 0; ii < arr[i].length; ++ii) {
        ...
    }
    ...
}

For objects, I use the following style:

Object.keys(obj).forEach(k => {
    var cValue = obj[k];
    // do something
});

To simplify this, I created iterate-object, which abstracts this functionality:

const iterateObject = require("iterate-object");
iterateObject(obj, (value, key) => {
    // do something
});

Binary and Ternary operators

See examples.

var foo = someObj
    .method()
    .method2()
    .method3()
    ;

var a = cond ? v1 : v2;

var b = long_condition_here
        ? v1 : v2
        ;

var c = another_long_condition_here
        ? with_some_long_value
        : or_another_some_long_value
        ;

Multiline strings 🎸

I use backticks to create multiline strings:

var multiLineStr = `Lorem ipsum dolor sit amet, consectetur adipisicing elit
sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat
New line again...`;

Modifying prototypes of built-in objects 💩

Just don't, unless that's the scope of the library.

Naming things 💭

Using camel case notation for variables, in general. For constructors I capitalize the variable name (e.g. EventEmitter).

// Node.JS require
const fs = require("fs")
    , events = require("events")
    , EventEmitter = events.EventEmitter
    ;

// Local variables
var x = 1
  , twoWords = "Hello World"
  ;

// Functions
function fooBar () {...}

// Classes
class Person {
    constructor (name, age) {
        this.name = name;
        this.age = age;
    }
    getName () {
        return this.name;
    }
}
// Object fields
var obj = {
    full_name: "Johnny B."
  , age: 20
};
obj.methodA = function () {...};

Curly braces ➰

Open the curly brace at the end of the line. Always put the instructions between curly braces, even there is only one instruction.

if (expr) {
    instr;
} else {
    instr2;
    instr3;
}

Array and Object Initializers 📁

See examples.

// Arrays
var arr = [1, 2, 3, 4];

var lotOfElms = [
    1, 2, 3, 4, 5, 6, 7
  , 8, 9, 10, 11, 12, 13
  , 14, 15, 16, 17, 18
];

var bigElms = [
    "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod."
  , "Tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim."
  , "Veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea."
  , "Commodo consequat. Duis aute irure dolor in reprehenderit in voluptate"
];

// Objects
var obj = { a: 1 };

var obj1 = {
    full_name: "Johnny B."
  , age: 20
};

Quotes

Double quotes, with some exceptions when single quotes are used.

var foo = "\"Hello\", he said.";
var jQuerySelector = "div.myClass[data-foo='bar']";

Comments

Use slashes for comments

Use slashes for both single line and multi line comments. Try to write comments that explain higher level mechanisms or clarify difficult segments of your code. Don't use comments to restate trivial things.

Right:

// 'ID_SOMETHING=VALUE' -> ['ID_SOMETHING=VALUE', 'SOMETHING', 'VALUE']
var matches = item.match(/ID_([^\n]+)=([^\n]+)/));

// This function has a nasty side effect where a failure to increment a
// redis counter used for statistics will cause an exception. This needs
// to be fixed in a later iteration.
function loadUser(id, cb) {
  // ...
}

var isSessionValid = (session.expires < Date.now());
if (isSessionValid) {
  // ...
}

Wrong:

// Execute a regex
var matches = item.match(/ID_([^\n]+)=([^\n]+)/);

// Usage: loadUser(5, function() { ... })
function loadUser(id, cb) {
  // ...
}

// Check if the session is valid
var isSessionValid = (session.expires < Date.now());
// If the session is valid
if (isSessionValid) {
  // ...
}

Put relevant comments. The comments start with uppercase letter.

// Dependencies
const lib1 = require("lib1")
    , lib2 = require("lib2")
    ;

// Constants
const FOURTY_TWO = 42;

Single line comments start with //. For multi-line commands, you use /* ... */

/* This is a single line comment */
// or
// This is a single line comment

/*
 And this is
 a multi-line
 comment
 */
 
 //or
 
// And this is
// a multi-line
// comment

If

Use if (expression) { ... } else { ... } to do something if expression is true or not.

let foo = 42;

if (foo > 40) {
    // do something
} else {
    // do something else
}

Switch

Description of the section

let planet = 'Earth';

switch (planet) {
  case "Mercury":
  case "Venus":
    console.log("Too hot here.");

  case 'Earth' :
    console.log("Welcome home!");
    break;

  case 'Mars' :
    console.log("Welcome to the other home!");
    break;

  case "Jupiter":
  case "Saturn":
  case "Uranus":
  case "Neptune":
  case "Pluto":
    console.log("You may get gold here.");
    break;

  default:
    console.log("Seems you found another planet.");
    break;
}

Primitive values

The following ones, are primitives:

  • Booleans: false, true
  • Numbers: 42, 3.14, 0b11010, 0x16, NaN (check out The magic of numbers)
  • Strings: 'Earth', "Mars"
  • Special values: undefined, null

Want to parse them ? try auto parse

Objects

The common way to declare objects is by using the curly braces:

let myObj = { world: "Earth" };

Attention: Objects are compared by reference. That being said, we have this:

let firstObj = {};
let secondObj = {};

// Check if they are equal
firstObj === secondObj
 false

// Comparing an object with itself...
firstObj === firstObj
 true

// Let's point the secondObj to firstObj
secondObj = firstObj

// Now they are equal
firstObj === secondObj
 true

Attention: you have no guarantee that adding the object keys in a specific order will get them in the same order. Object keys are not ordered, even in general JavaScript interpreters which will iterate them in the order of adding them in the object (again, do not rely on this feature).

Arrays

In addition to objects, the array data is ordered by indexes. Arrays are actually objects, having the indexes (numbers from 0 to legnth - 1) as keys.

let fruits = ["apples", "pears", "oranges"];

fruits[1]
 "pears"
Access, add, remove, and update elements
> let fruits = ["Apple"]

// Add to the end of the array
> fruits.push("Pear")
2 // < The new length of the array

 [ 'Apple', 'Pear' ]
 //         ^ This was just added

// Add to the start of the array
> fruits.unshift("Orange")
3 // < The new length of the array

 [ 'Orange', 'Apple', 'Pear' ]
 // ^ This was just added

// Access the element at index 1 (the second element)
> fruits[1]
'Apple'

// How many items do we have?
> fruits.length
3

// Turn the Apple into Lemon
> fruits[1] = "Lemon"
'Lemon'

 [ 'Orange', 'Lemon', 'Pear' ]
 //          ^ This was before an Apple

// Insert at index 1 a new element
> fruits.splice(1, 0, "Grapes")
[] // < Splice is supposed to delete things (see below)
   //   In this case we're deleting 0 elements and
   //   inserting one.

 [ 'Orange', 'Grapes', 'Lemon', 'Pear' ]
 //          ^ This was added.

// Get the Lemon's index
> fruits.indexOf("Lemon")
2

// Delete the Lemon
> fruits.splice(2, 1)
[ 'Lemon' ]

 [ 'Orange', 'Grapes', 'Pear' ]
 //                   ^ Lemon is gone

// Remove the last element
> fruits.pop()
'Pear'

 [ 'Orange', 'Grapes' ]
 //                  ^ Pear is gone

// Remove the first element
> fruits.shift()
'Orange'

   [ 'Grapes' ]
 // ^ Orange is gone
Iterating over Arrays

There are few ways to loop trough an array.

// Using for-loop
var arr = [42, 7, -1]
for (var index = 0; index < arr.length; ++index) {
    var current = arr[index];
    /* Do something with `current` */
}

// Others prefer defining an additional `length` variable:
for (var index = 0, length = arr.length; index < length; ++index) {
    var current = arr[index];
    /* ... */
}

// Another way i using `forEach`:
arr.forEach((current, index, inputArray) => {
    /* Do something with `current` */
});

// Or using the for ... of:
for (let current of arr) {
    /* current will be the current element */
}

Functions

There are a couple of ways to define functions in JavaScript. The common uses are:

function sum (a, b) {
    return a + b;
}

var sum = function (a, b) {
    return a + b;
}

// Using the ES6 arrow functions
let sum = (a, b) => a + b;

Then you can call the function like:

let result = sum(40, 2);
// => 42

Constructors and Classes

Description of the section

SUGGEST DESIGN PATTERNS

There are a couple of ways you can obtain a class-like functionality in JavaScript.

Factory functions Creating an object and returning it.

function Person (name) {
   var self = {};

   // Public field
   self.name = name;

   // Public method
   self.getName = function () {
     // `this` is the `self`
     return this.name;
   };

   return self;
}

var p = Person("Alice");
console.log(p.getName());
// => "Alice"

Using prototypes By adding a method in the prototype object of a function, you're adding that method as a public method to all the instances of that class.

function Person (name) {
  this.name = name;
}

Person.prototype.getName = function () {
  // `this` is the `self`
  return this.name;
};

var p = new Person("Bob");
console.log(p.getName());
// => "Bob"

Using ES6 classes

class Person {
  constructor (name) {
    this.name = name;
  }
  getName () {
    return this.name;
  }
}

var p = new Person("Carol");
console.log(p.getName());
// => "Bob"

It's also very easy to inherit classes in ES6:

class Musician extends Person {
   constructor (name, instrument) {
     // Call the base class
     super(name);

     this.instrument = instrument;
   }

   play () {
     console.log(`${this.getName()} is playing ${this.instrument}`);
   }
}

var me = new Musician("Johnny B.", "piano");

// Get the name of the musician, who is also a person
console.log(me.getName());
// => "Johnny B."

me.play();
// => "Johnny B. is playing piano."

Async vs Sync

Sometimes you have to wait a little bit for things to be done: such as when making a cake, you have to work on it and you have to wait a while for it to be ready. Most familiar things in our lives are asynchronous.

Sync Usually, synchronous operations send the response directly, using the return keyword:

// Synchronous sum function sum (a, b) { return a + b; } var result = sum(40, 2); // => 42 Async To have an async function, you need a source of async stuff. In this example, we will use the setTimeout function. It accepts a function as first argument (which is called callback function) and a number as second argument—representing the time delay after the function is called:

function asyncSum (a, b, cb) { setTimeout(function () { cb(a + b); // -----------+ This is the place }, 1000); // | where we call then } // V callback function asyncSum(40, 2, function (result) { console.log(result); // => 42 });

// Style

What are callbacks?

callbacks are functions which are sent as an argument to another function and are invoked when something happens.

function Cake() { /* Just a dummy class-like constructor for now */ }

// We won't make a ckae if we're busy
var busy = false;

function makeCake ( callback) {
  // If we're busy making a cake, send back an error
  if (busy) {
    return callback(new Error("Already busy with creating a cake. Please wait a bit and try again later."));
  }
  // Well, if we weren't busy before, we are now
  busy = true;

  // Wait one second
  setTimeout(function () { // <- This is a callback function too. It is called after one second.

    // After one second we call the callback function
    callback(null, new Cake());

    // After sending the cake, we're not busy anymore
    busy = false;
  }, 1000);
}

makeCake(function (err, cake) {
  if (err) { console.error(err); }
  console.log("Made a cake.");
  // => "Made a cake."
});

// This will end with an error because we're busy already
makeCake(function (err, cake) {
  if (err) { console.error(err); }
  // !=> "Already busy with creating a cake. Please wait a bit and try again later."
  console.log("Made a cake.");
});

// Wait 2 seconds
setTimeout(function () {
  // This will work again
  makeCake(function (err, cake) {
    if (err) { console.error(err); }
    console.log("Made a cake.");
    // => "Made a cake."
  });
}, 2000);

Promises

There is a thing called Promise. Let's see an example:

function sum (a, b) {
   return Promise(function (resolve, reject) {
     // Let's wait a second and only then send the response
     setTimeout(function () {
       if (typeof a !== "number" || typeof b !== "number") {
         return reject(new TypeError("Please provide two numbers to sum."));
       }
       resolve(a + b);
     }, 1000);
   });
}

var myPromise = sum(40, 2);

myPromsise.then(function (result) {
  // After one second we have the response here
  console.log("> Summed 40 + 2: ", result);

  // Let's pass some invalid data and return another promise
  return sum(null, "foo");
}).then(function () {
  // This won't be called because we have an error
}).catch(function (err) {
  // Instead, this `catch` handler is called: (after another second)
  console.error(err);
  // => Please provide two numbers to sum.
});

A promise can be in one of these three states:

  • pending: the operation is pending
  • fulfilled: the operation was finished
  • rejected: an error appeared, so the promise is rejected

StackOverflow Documention has a good section about promises here.

Create and throw errors

To create an error, you have to use the Error constructor:

let myError = new Error("Something went really wrong.");

// You can even append custom data here
myError.code = "MY_FANCY_ERROR_CODE";

To throw an error, you have to use the throw statement:

throw new Error("Something bad happened."); There are few types of errors. For example, if you validate the arguments passed to a function, use TypeError:

function sayHello(message) {
  if (typeof message !== "string") {
    throw new TypeError("The message should be a string.");
  }
  console.log(message);
}
Callbacks

When you have a callback interface it's friendlier to send the errors using the callback functions.

Promises

In the Promises (even on the interface) it's friendlier to send the errors using the reject functions.

Error handling

In general, it is a good practice to validate the data you're passing to function (especially when they are coming from the user input). This way you can avoid TypeErrors to be thrown.

If there's a function which throws an error by design, you can catch it using try - catch:

function assert (truly) {
  if (!truly) {
    throw new Error("Not true.");
  }
}

try {
  // This will *not* throw an error
  assert(42 === 42);

  // This will throw an error, so that will go in the catch
  assert(42 === -1);

  // Everything put after the place where the error was thrown
  // is not executed
} catch (e) {
  console.error(e);
  // => Not true.
}

Note if you have an async function (either callback-based or which returns a promise), you'll do something like this:

// Callback
fetchDataFromServer(function (err, data) {
  if (err) {
    /* do something if you have an error */
  } else {
    /* Do something with `data` */
  }
});

// Promise
fetchDataFromServer().then(function (data) {
    /* Do something with `data` */
}).catch(function (err) {
    /* do something if you have an error */
});

Try catch

Description of the section

// Style

Incrementing/decrementing numbers

You can increment a variable name x using ++x or x++. Similarly, you can decrement it by --x or x--.

The difference is that ++x (--x) returns the incremented (decremented) value, while x++ (x--) returns the previous value of x.

// Let's declare x
let x = 42;

// Store in y, the result of ++x
let y = ++x;

// Let's see the result
console.log(`x is ${x} and y is ${y}`);
 'x is 43 and y is 43'

// Now, store in y the result of x++. Note, x is now 43.
y = x++;

// Let's see again
console.log(`x is ${x} and y is ${y}`);
 'x is 44 and y is 43'

// So, `y` is 43, because `x++` returned the pre-incremented value (which was 43)

Loops

This will print all the integers from 1 to 42.

for
for (var i = 1; i <= 42; ++i) {
  console.log(i);
}

Using for ... in ... can be used to iterate object keys:

var name = {
  first: "Johnny",
  last: "B."
};

for (var key in name) {
  if (name.hasOwnProperty(key)) {
    console.log(key, name[key]);
    // "first", "Johnny"
    // "last", "B."
  }
}

In ES6 there is a for ... of ... as well. It's pretty neat since it iterates any iterable objects (arrays, strings etc).

let numbers = [-1, 7, 42, 64];
for (let num of numbers) {
  console.log(num);
}
// -1
// 7
// 42
// 64
while

var i = 1;
while (i <= 42) {
    console.log(i);
    ++i;
}
do - while

var i = 0;
do {
    ++i;
    console.log(i);
} while (i < 42);

Regular expressions

Regular expressions are a lot of fun. They are delimited by slashes:

/^[0-9]+$/gm.test("a")
// => false

/^[0-9]+$/gm.test("42")
// => true

A regular expression has a pattern and flags. The pattern in this example is ^[0-9]+$—meaning if the input is one or more digits (from 0 to 9), we validate it—while the flags are g (global) and m (multiline).

regex101.com is a good resource for visualizing and sharing regular expressions with others:

javascript cheat sheet

Regular expressions can be used to match things in strings, such as numbers:

// Get all the numbers from this input (note you'll get an array of strings)
> "Alice was born in 1974, so she's 42 years old in 2016.".match(/[0-9]+/g)
[ '1974', '42', '2016' ]

// Want to get numbers? Map them using the `Number` function
> "Alice was born in 1974, so she's 42 years old in 2016.".match(/[0-9]+/g).map(Number)
[ 1974, 42, 2016 ]

// BE CAREFUL that if there's no match `match` will return `null`
> "Bob is seven years old.".match(/[0-9]+/g)
null

Also, they can be used to replace parts of the strings:

// Mask all the digits of a credit card number, but the last 4

"1234234534564567".replace(/\d(?=\d{4})/g, "*"); '************4567'

// Style

Useful Math functions and constants

// Get the PI number
> Math.PI
3.141592653589793

// Get the E number
> Math.E
2.718281828459045

// Maximum between two numbers
> Math.max(7, 42)
42

// Minimum between numbers (arguments)
> Math.min(7, 42, 255, 264)
7

// Power
> Math.pow(2, 4)
16

// Random number between 0 (inclusive) and 1 (exclusive)
> Math.random()
0.2114640628617317

// Round
> Math.round(41.8)
42

There are trigonometric functions as well: sin, cos, tan, atan etc. Note these require radians. One radian is 180 degrees.

Dates

Use the Date constructor to create date objects.

var now = new Date();
now.getFullYear();
// => 2016

If you want to have fancy stuff like formatting dates, etc., use libraries like moment.

Naming Conventions

Use lowerCamelCase for variables, properties and function names

Variables, properties and function names should use lowerCamelCase. They should also be descriptive. Single character variables and uncommon abbreviations should generally be avoided.

Right:

var adminUser = db.query('SELECT * FROM users ...');
Wrong:

var admin_user = db.query('SELECT * FROM users ...');
Use UpperCamelCase for class names

Class names should be capitalized using UpperCamelCase.

Right:

function BankAccount() {
}
Wrong:

function bank_Account() {
}
Use UPPERCASE for Constants

Constants should be declared as regular variables or static class properties, using all uppercase letters.

Right:

var SECOND = 1 * 1000;

function File() {
}
File.FULL_PERMISSIONS = 0777;
Wrong:

const SECOND = 1 * 1000;

function File() {
}
File.fullPermissions = 0777;

Functions

Write small 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.

Return early from functions

To avoid deep nesting of if-statements, always return a function's value as early as possible.

Right:

function isPercentage(val) {
  if (val < 0) {
    return false;
  }

  if (val > 100) {
    return false;
  }

  return true;
}
Wrong:

function isPercentage(val) {
  if (val >= 0) {
    if (val < 100) {
      return true;
    } else {
      return false;
    }
  } else {
    return false;
  }
}

Or for this particular example it may also be fine to shorten things even further:

function isPercentage(val) {
  var isInRange = (val >= 0 && val <= 100);
  return isInRange;
}
Name your closures

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');
});
No nested closures

Use closures, but don't nest them. Otherwise your code will become a mess.

Right:

setTimeout(function() {
  client.connect(afterConnect);
}, 1000);

function afterConnect() {
  console.log('winning');
}
Wrong:

setTimeout(function() {
  client.connect(function() {
    console.log('losing');
  });
}, 1000);
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;
  });

Stay Away from

Object.freeze, Object.preventExtensions, Object.seal, with, eval

Crazy shit that you will probably never need. Stay away from it.

Requires At Top

Always put requires at top of file to clearly illustrate a file's dependencies. Besides giving an overview for others at a quick glance of dependencies and possible memory impact, it allows one to determine if they need a package.json file should they choose to use the file elsewhere.

Getters and setters

Do not use setters, they cause more problems for people who try to use your software than they can solve.

Feel free to use getters that are free from side effects, like providing a length property for a collection class.

Do not extend built-in prototypes

Do not extend the prototype of native JavaScript objects. Your future self will be forever grateful.

Right:

var a = [];
if (!a.length) {
  console.log('winning');
}
Wrong:

Array.prototype.empty = function() {
  return !this.length;
}

var a = [];
if (a.empty()) {
  console.log('losing');
}

Standard js

Rules
  • Use 2 spaces for indentation.

    function hello (name) {
      console.log('hi', name)
    }
  • Use single quotes for strings except to avoid escaping.

    console.log('hello there')
    $("<div class='box'>")
  • No unused variables.

    function myFunction () {
      var result = something()   // ✗ avoid
    }
  • Add a space after keywords.

    if (condition) { ... }   // ✓ ok
    if(condition) { ... }    // ✗ avoid
  • Add a space before a function declaration's parentheses.

    function name (arg) { ... }   // ✓ ok
    function name(arg) { ... }    // ✗ avoid
    
    run(function () { ... })      // ✓ ok
    run(function() { ... })       // ✗ avoid
  • Always use === instead of ==.
    Exception: obj == null is allowed to check for null || undefined.

    if (name === 'John')   // ✓ ok
    if (name == 'John')    // ✗ avoid
    if (name !== 'John')   // ✓ ok
    if (name != 'John')    // ✗ avoid
  • Infix operators must be spaced.

    // ✓ ok
    var x = 2
    var message = 'hello, ' + name + '!'
    // ✗ avoid
    var x=2
    var message = 'hello, '+name+'!'
  • Commas should have a space after them.

    // ✓ ok
    var list = [1, 2, 3, 4]
    function greet (name, options) { ... }
    // ✗ avoid
    var list = [1,2,3,4]
    function greet (name,options) { ... }
  • Keep else statements on the same line as their curly braces.

    // ✓ ok
    if (condition) {
      // ...
    } else {
      // ...
    }
    // ✗ avoid
    if (condition) {
      // ...
    }
    else {
      // ...
    }
  • For multi-line if statements, use curly braces.

    // ✓ ok
    if (options.quiet !== true) console.log('done')
    // ✓ ok
    if (options.quiet !== true) {
      console.log('done')
    }
    // ✗ avoid
    if (options.quiet !== true)
      console.log('done')
  • Always handle the err function parameter.

    // ✓ ok
    run(function (err) {
      if (err) throw err
      window.alert('done')
    })
    // ✗ avoid
    run(function (err) {
      window.alert('done')
    })
  • Always prefix browser globals with window..
    Exceptions are: document, console and navigator.

    window.alert('hi')   // ✓ ok
  • Multiple blank lines not allowed.

    // ✓ ok
    var value = 'hello world'
    console.log(value)
    // ✗ avoid
    var value = 'hello world'
    
    
    console.log(value)
  • For the ternary operator in a multi-line setting, place ? and : on their own lines.

    // ✓ ok
    var location = env.development ? 'localhost' : 'www.api.com'
    
    // ✓ ok
    var location = env.development
      ? 'localhost'
      : 'www.api.com'
    
    // ✗ avoid
    var location = env.development ?
      'localhost' :
      'www.api.com'
  • For var declarations, write each declaration in its own statement.

    // ✓ ok
    var silent = true
    var verbose = true
    
    // ✗ avoid
    var silent = true, verbose = true
    
    // ✗ avoid
    var silent = true,
        verbose = true
  • Wrap conditional assignments with additional parentheses. This makes it clear that the expression is intentionally an assignment (=) rather than a typo for equality (===).

    // ✓ ok
    while ((m = text.match(expr))) {
      // ...
    }
    
    // ✗ avoid
    while (m = text.match(expr)) {
      // ...
    }
Semicolons
  • No semicolons. (see: 1, 2, 3)

    window.alert('hi')   // ✓ ok
    window.alert('hi');  // ✗ avoid
  • Never start a line with (, [, or `. This is the only gotcha with omitting semicolons, and standard protects you from this potential issue.

    // ✓ ok
    ;(function () {
      window.alert('ok')
    }())
    
    // ✗ avoid
    (function () {
      window.alert('ok')
    }())
    // ✓ ok
    ;[1, 2, 3].forEach(bar)
    
    // ✗ avoid
    [1, 2, 3].forEach(bar)
    // ✓ ok
    ;`hello`.indexOf('o')
    
    // ✗ avoid
    `hello`.indexOf('o')

    Note: If you're often writing code like this, you may be trying to be too clever.

    Clever short-hands are discouraged, in favor of clear and readable expressions, whenever possible.

    Instead of this:

    ;[1, 2, 3].forEach(bar)

    This is much preferred:

    var nums = [1, 2, 3]
    nums.forEach(bar)
// Style

JS Fiddle Examples

Description of the section

// Style

Mean Stack Style

Angular Style

Express Style

Markdown Style

  • Headers
  • Emphasis
  • Lists
  • Links - these
  • Images
  • Code
  • Tables
  • Block Quotes
  • Inline HTML
  • Horizontal Rules
  • Line Breaks
  • Video Embedding

Common Mistakes

  • Not using development tools
  • Blocking the event loop
  • Executing a callback multiple times
  • The Christmas tree of callbacks (Callback Hell)
  • Creating big monolithic applications
  • Poor logging
  • No tests
  • Not using static analysis tools
  • Zero monitoring or profiling
  • Debugging with console.log

Tools

Text Editors

Sublime 3 or Atom

Markdown

Mongo View

Debugs

Other tools

Installs & Versions

Framework/Library/Program Version
Angular 1.X
JQuery 3.X
NodeJs 6.X
Centos 7
NodeJs 6.X

Blogs

This section is devoted to blogs that just talk about and have alot of great content. Please reach out and contact me if you think i should have yours in here.

Github

coming soon

More Resources

coming soon

Bootcamps

coming soon

Courses

coming soon

Mentee

coming soon

Contribute

coming soon

Future

coming soon

License

coming soon

Old VERSION BELOW

Control Flow

###run-auto

Installation

npm install run-auto --save
Usage
var auto = require('run-auto')

auto({
  getData: function (callback) {
    console.log('in getData')
    // async code to get some data
    callback(null, 'data', 'converted to array')
  },
  makeFolder: function (callback) {
    console.log('in makeFolder')
    // async code to create a directory to store a file in
    // this is run at the same time as getting the data
    callback(null, 'folder')
  },
  writeFile: ['getData', 'makeFolder', function (results, callback) {
    console.log('in writeFile', JSON.stringify(results))
    // once there is some data and the directory exists,
    // write the data to a file in the directory
    callback(null, 'filename')
  }],
  emailLink: ['writeFile', function (results, callback) {
    console.log('in emailLink', JSON.stringify(results))
    // once the file is written let's email a link to it...
    // results.writeFile contains the filename returned by writeFile.
    callback(null, { file: results.writeFile, email: 'user@example.com' })
  }]
}, function(err, results) {
  console.log('err = ', err)
  console.log('results = ', results)
})
// With Multiple Mongo Calls
auto({
    blogs: function (cb) {
      blogs
        .find()
        .populate('user')
        .exec(cb)
    },
    users: function (cb) {
      users
        .find()
        .populate('user')
        .exec(cb)
    },
    tester: function (cb) {
      tester
        .find()
        .populate('user')
        .exec(cb)
    },
    todos: function (cb) {
      todos
        .find()
        .populate('user')
        .exec(cb)
    }
  }, function (err, results) {
    if (err) return next(err)
    return res.status(200).send(results)
  })

Mongodb

Installation

Database-as-a-Service

Mlab

Mongoose

###mongoose-validator

Installation

$ npm install mongoose-validator --save

Usage

var mongoose = require('mongoose');
var validate = require('mongoose-validator');

var nameValidator = [
  validate({
    validator: 'isLength',
    arguments: [3, 50],
    message: 'Name should be between {ARGS[0]} and {ARGS[1]} characters'
  }),
  validate({
    validator: 'isAlphanumeric',
    passIfEmpty: true,
    message: 'Name should contain alpha-numeric characters only'
  })
];

var Schema = new mongoose.Schema({
  name: {type: String, required: true, validate: nameValidator}
});

ExpressJS Style

Installation

npm install express-validator --save

Usage

var util = require('util'),
    express = require('express'),
    expressValidator = require('express-validator'),
    app = express.createServer();

app.use(express.bodyParser());
app.use(expressValidator([options])); // this line must be immediately after express.bodyParser()!

app.post('/:urlparam', function(req, res) {

  // VALIDATION
  req.assert('postparam', 'Invalid postparam').notEmpty().isInt();
  req.assert('urlparam', 'Invalid urlparam').isAlpha();
  req.assert('getparam', 'Invalid getparam').isInt();

  // SANITIZATION
  // as with validation these will only validate the relevent param in all areas
  req.sanitize('postparam').toBoolean();

  var errors = req.validationErrors();
  if (errors) {
    res.send('There have been validation errors: ' + util.inspect(errors), 400);
    return;
  }
  res.json({
    urlparam: req.params.urlparam,
    getparam: req.params.getparam,
    postparam: req.params.postparam
  });
});

app.listen(8888);

Options

Api Options

Installation
npm install validator --save
Usage
var validator = require('validator');

validator.isEmail('foo@bar.com'); //=> true
Options

Api Options

Versions

Text Editor

About

Green Pioneer Solutions Style Guide to all things we develop

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published