MercadoLibre JavaScript Style Guide.
The main goal of this guide is to set standards for writing our JavaScript files and components, helping the readability and maintainability of our code. By doing this, we can significantly reduce the time required to understand any front-end implementation.
By writing clean code, we are able to:
- achieve a code that’s easier to understand;
- detect errors and potential problems;
- easily identify what code can be reused;
- build or update any functionality on any code already implemented;
- work on any file regardless of who wrote it.
"Consistent code, even when written by a team, should look like one person wrote it." by Addy Osmani
Based on:
- Comments
- Spacing
- Commas & Semicolons
- Literals
- Operators
- Variables
- Functions
- Loops
- Events
- Conditionals
- Module Pattern
- Linting
-
All your code should be documented.
-
Use single-line comment to add hints, notes, suggestions or warnings.
-
Use multiple-line comment for formal documentation.
-
Use JSDoc3.
/** * Returns a shallow-copied clone of a given object. * @param {Object} obj A given object to clone. * @returns {Object} * @example * clone(object); */ function clone(obj) { // TODO: We need to develop it. };
-
Don't put whitespace at the end of line or on blank lines.
// DON'T function foo() { console.log('foobar');···· };··
-
Don't mix spaces and tabs.
// DON'T function foo() { ····console.log('foobar'); ----console.log('bar'); };
-
Use 4 spaces for indentation. Don't use tabs.
// DON'T function foo() { ----console.log('foobar'); }; // DON'T function foo() { ··console.log('foobar'); };
// DO function foo() { ····console.log('foobar'); };
### Commas
-
Don't start with comma.
// DON'T var map = { 'foo': 'foo' , 'bar': 'bar' , 'foobar': 'foobar' };
-
Don't put the comma at the end of the last property. Trailing commas in object literals are legal in ECMAScript 5, but don't use it for the time being.
// DON'T var map = { 'foo': 'foo', 'bar': 'bar', 'foobar': 'foobar', };
-
Put the comma at the end of the line.
// DO var map = { 'foo': 'foo', 'bar': 'bar', 'foobar': 'foobar' };
### Semicolons
-
Don't put semicolons at the end of
-
loops statements (
for
,for...in
andwhile
)// DON'T for (var i = 0; i < 10; i += 1) { console.log('foobar'); };
// DO for (var i = 0; i < 10; i += 1) { console.log('foobar'); }
-
conditionals statements (
if...else
,switch
)// DON'T if (foo !== undefined) { console.log('foobar'); };
// DO if (foo !== undefined) { console.log('foobar'); }
-
funcions declarations
// DON'T function foo() { console.log('foobar'); };
// DO function foo() { console.log('foobar'); }
-
-
Always put a semicolon at the end of the line.
// DON'T (function () { var foo = 'foobar' return foo }())
// DO (function () { var foo = 'foobar'; return foo; }());
-
Use the array literal notation.
// DON'T var foo = new Array();
// DO var foo = [];
-
Use the object literal notation.
// DON'T var foo = new Object();
// DO var foo = {};
-
Use one space between operators.
// DON'T foo||bar;
// DO foo·||·baz;
-
Use the assignment operator instead the increment or decrement operator.
// DON'T foo++;
// DO foo += 1;
-
Use one space between operators.
// DON'T (1+2)*3;
// DO (1·+·2)·*·3;
-
Variable names should be nouns (don't worry about length).
-
Don't use global variables.
// DON'T foo = 'bar';
-
Name it in lowerCamelCase.
-
Use one space before and after assignment.
// DON'T var foo='bar';
// DO var foo·=·'bar';
-
Declare many variables in one statement. Use different lines for each variable.
// DON'T var foo; var bar; var baz; // DON'T var foo, bar, baz;
// DO var foo, bar, baz;
-
Begin with $ the name of variables that contains a jQuery/Zepto element.
// DON'T var container = $('#foo');
// DO var $container = $('#foo');
-
Define all variables on top.
// DON'T var foo; bar(); var baz = 'example';
// DO var foo, baz; bar(); baz = 'example';
-
Function names should begin with a verb.
// DON'T function name(){ // ... }
// DO function getName(){ // ... }
-
Function return booleans should begin with
is
orhas
.// DON'T function error(){ // ... }
// DO function hasError(){ // ... }
-
Define all variables at the top of the function body.
-
Indent the function body.
-
Name it in lowerCamelCase, unless it be a constructor function. In that case name it in CamelCase.
-
Return
this
in all your public methods. -
Keep the name and the parenthesis together. Use a space only after parenthesis.
// DON'T function foo·()·{ // ... } // DON'T function foo·(){ // ... }
// DO function foo()·{ // ... }
-
On function expressions, use a space before and after the parenthesis.
// DON'T var foo = function(){ // ... }
// DO var foo = function·()·{ // ... }
-
Don't put semicolon at the end of the function declarations.
// DON'T function foo() { // ... };
// DO function foo() { // ... }
-
Only put a semicolon at the end of the function expressions.
// DON'T var foo = function () { // ... }
// DO var foo = function () { // ... };
-
Constructor functions must be executed with
new
. -
Wrap the entire function execution in parenthesis.
// DON'T var foo = (function () { // ... })();
// DO var foo = (function () { // ... }());
-
Use
that
to grab the reference tothis
scope.// DO var that = this;
-
Use
that
only for contexts thatthis
can't reach.// DON'T var that = this; that.addEventListener('click', function () { that.foo = 'example'; });
// DO var that = this; this.addEventListener('click', function () { that.foo = 'example'; });
-
Dont't use the increment operator.
-
Don't calculate the length on each iteration.
-
Don't put semicolon at the end of the for statement.
-
Declare variables outside of the for statement.
-
Put opening brace on the same line.
-
Put a space between 'for' and '('.
-
Put a space between ')' and '{'.
// DON'T for(i = 0; i < foo.length; i++){ console.log('foobar'); }; // DON'T for(var i = 0; i < foo.length; i++){ console.log('foobar'); }; // DON'T for(i = 0; i < foo.length; i++) { console.log('foobar'); }; // DON'T for(x in foo){ console.log('foobar'); }; // DON'T for(var x in foo){ console.log('foobar'); };
// DO var i = 0, len = foo.length; for·(i; i < len; i += 1)·{ console.log('foobar'); } // DO var x; for·(x in foo)·{ console.log('foobar'); }
-
Don't calculate the length on each iteration.
-
Don't put semicolon at the end of the while statement.
-
Put opening brace on the same line.
-
Put a space between 'while' and '('.
-
Put a space between ')' and '{'.
// DON'T var i = 0; while(i < foo.length){ console.log('foobar'); i++; }; // DON'T var i = 0; while(i < foo.length) { console.log('foobar'); i++; };
// DO var i = 0, len = foo.length; while·(i < len)·{ console.log('foobar'); i += 1; }
-
Put semicolon at the end of the do...while statement.
-
Don't calculate the length on each iteration.
-
Put opening brace on the same line.
-
Put a space between 'do' and '{'.
-
Put a space between '}' and 'while'.
-
Put a space between 'while' and '('.
-
Put a space between ')' and '{'.
// DON'T var i = 0; do{ i++; console.log(i); }while (i < 5) // DON'T var i = 0; do { i++; console.log(i); }while (i < 5)
// DO var i = 0; do·{ i += 1; console.log(i); }·while·(i < 5);
-
Use
forEach
statement to iterate an array.arr.forEach(function (x) { console.log(x); });
-
- Name it in lowercases without spaces.
- Define namespaces on event names.
// DON'T $(document).on('click', function () { ... }); $(document).on('mouseenter', function () { ... }); $(document).on('scroll', function () { ... }); $(document).off('click'); $(document).off('mouseenter');
// DO $(document).on('click.foo', function () { ... }); $(document).on('mouseenter.foo', function () { ... }); $(document).on('scroll.bar', function () { ... }); $(document).off('.foo');
-
Use one space wrapping the condition parenthesis.
// DON'T if(foo){ bar(); } // DON'T if(·foo·){ bar(); }
// DO if·(foo)·{ bar(); }
-
Use a new line for statements.
// DON'T if (foo) { bar(); }
// DO if (foo) { bar(); }
-
Use curly braces always.
// DON'T if (foo) bar(); // DON'T if (foo) bar();
// DO if (foo) { bar(); }
-
Don't put semicolon at the end.
// DON'T if (foo) { bar(); };
// DO if (foo) { bar(); }
-
Compare with
undefined
when it's not a boolean.// DON'T if (baz) { foo(); }
// DO if (baz !== undefined) { foo(); }
-
Use
===
and!==
operators.// DON'T if (baz == 'example') { foo(); }
// DO if (baz === 'example') { foo(); }
-
Avoid
else if
when possible. Useif
andelse
instead.// DON'T if (foo !== undefined) { // statement 1 } else if (bar !== undefined) { // statement 2 } else { // statement 3 }
// DO if (foo !== undefined) { // statement 1 return; } if (bar !== undefined) { // statement 2 return; } // statement 3
-
Create a component into a file with the same name.
-
Should start with an Immediately-Invoked Function Expression (IIFE).
-
Use
'use strict';
at the top of the IIFE. -
Declare methods on its
prototype
property. -
Private members should be named with a trailing underscore.
-
Use
events
instead ofcallbacks
. -
Keep your components small.
// myComponent.js (function (window) { 'use strict'; function MyComponent() {...}; MyComponent.prototype._private = function () {...}; MyComponent.prototype.public = function () {...}; // Expose component window.MyComponent = MyComponent; }(this));
-
Use JSLint, JSHint or ESLint to:
- detect errors and potential problems;
- improves your quality code;
- avoids unused variables;
- identifies problematic styles and patterns in your code;
- reduces any syntax confusion.
-
Use
jslint
with the following configuration:/*jslint browser: true, ass: true, nomen: true, regexp: true, todo: true, indent: 4 */
-
Use
jshint
with the following configuration:{ "curly": true, "eqeqeq": true, "es3": true, "forin": true, "freeze": true, "immed": true, "indent": true, "latedef": true, "newcap": true, "noarg": true, "plusplus": true, "quotmark": "single", "undef": true, "unused": true, "strict": true, "trailing": true, "asi": true, "eqnull": true, "evil": true, "expr": true, "funcscope": true, "globalstrict": true, "laxcomma": true, "loopfunc": true, "smarttabs": true, "shadow": true, "sub": true, "supernew": true }
-
Use
eslint
with the following basic configuration:{ "env": { "browser": true, "jquery": true }, "rules": { "block-scoped-var": [0], "comma-dangle": [2], "comma-style": [2, "last"], "curly": [2], "dot-notation": [0], "eqeqeq": [2], "guard-for-in": [1], "indent": [2], "no-array-constructor": [2], "no-caller": [2], "new-cap": [2], "no-eq-null": [0], "no-eval": [2], "no-extend-native": [2], "no-extra-semi": [2], "no-loop-func": [0], "no-mixed-spaces-and-tabs": [2], "no-new-wrappers": [2], "no-new-object": [2], "no-plusplus": [2], "no-shadow": [0], "no-spaced-func": [2], "no-trailing-spaces": [2], "no-undef": [2], "no-unused-expressions": [2], "no-unused-vars": [1, {"vars": "all", "args": "after-used"}], "no-use-before-define": [2], "quotes": [2, "single", "avoid-escape"], "space-after-keywords": [2, "always"], "space-before-blocks": [2, "always"], "space-before-function-paren": [2, {"anonymous": "always", "named": "never"}], "space-in-parens": [2, "never"], "space-infix-ops": [2], "space-return-throw-case": [2], "strict": [2, "global"], "vars-on-top": [2] } }
## License
Licensed under the MIT license.
Copyright (c) 2013 MercadoLibre.