GitHub - dvasuta/javascript: JavaScript Style Guide


  **[[⬆]](#TOC)**


## <a name='whitespace'>Whitespace</a>

- Use soft tabs set to 2 spaces

  ```javascript
  // bad
  function∙() {
  ∙∙∙∙var name;
  }

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

  // good
  function∙() {
  ∙∙var name;
  }
  ```

- No end of line whitespace.

- No blank line whitespace.

- Place one space before and after binary and ternary operators.

  ```javascript
  var a∙=∙1∙+∙2,
    b∙=∙a++,
    c∙=∙a∙>∙0∙?∙'yes'∙:∙'no';
  ```

- Place 1 space before the leading brace.

  ```javascript
  // bad
  function test(){
    console.log('test');
  }

  // good
  function test ()∙{
    console.log('test');
  }

  // bad
  dog.set('attr',{
    age: '1 year',
    breed: 'Bernese Mountain Dog'
  });

  // good
  dog.set('attr',∙{
    age: '1 year',
    breed: 'Bernese Mountain Dog'
  });
  ```
- Place an empty newline at the end of the file.

  ```javascript
  // bad
  (function (global) {
    // ...stuff...
  })(this);
  ```

  ```javascript
  // good
  (function (global) {
    // ...stuff...
  })(this);

  ```

- Use indentation when making long method chains.

  ```javascript
  // bad
  $('#items').find('.selected').highlight().end().find('.open').updateCount();

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

  // bad
  var leds = stage.selectAll('.led').data(data).enter().append("svg:svg").class('led', true)
      .attr('width',  (radius + margin) * 2).append("svg:g")
      .attr("transform", "translate(" + (radius + margin) + "," + (radius + margin) + ")")
      .call(tron.led);

  // good
  var leds = stage.selectAll('.led')
      .data(data)
    .enter().append("svg:svg")
      .class('led', true)
      .attr('width',  (radius + margin) * 2)
    .append("svg:g")
      .attr("transform", "translate(" + (radius + margin) + "," + (radius + margin) + ")")
      .call(tron.led);
  ```

  **[[⬆]](#TOC)**

## <a name='leading-commas'>Leading Commas</a>

- **Nope.**

  ```javascript
  // bad
  var once
    , upon
    , aTime;

  // good
  var once,
      upon,
      aTime;

  // bad
  var hero = {
      firstName: 'Bob'
    , lastName: 'Parr'
    , heroName: 'Mr. Incredible'
    , superPower: 'strength'
  };

  // good
  var hero = {
    firstName: 'Bob',
    lastName: 'Parr',
    heroName: 'Mr. Incredible',
    superPower: 'strength'
  };
  ```

  **[[⬆]](#TOC)**


## <a name='semicolons'>Semicolons</a>

- **Yup.**

  ```javascript
  // bad
  (function () {
    var name = 'Skywalker'
    return name
  })()

  // good
  (function () {
    var name = 'Skywalker';
    return name;
  })();

  // good
  ;(function () {
    var name = 'Skywalker';
    return name;
  })();
  ```

  **[[⬆]](#TOC)**


## <a name='type-coercion'>Type Casting & Coercion</a>
- Perform type coercion at the beginning of the statement.
- Strings:

  ```javascript
  //  => this.reviewScore = 9;

  // bad
  var totalScore = this.reviewScore + '';

  // good
  var totalScore = '' + this.reviewScore;

  // bad
  var totalScore = '' + this.reviewScore + ' total score';

  // good
  var totalScore = this.reviewScore + ' total score';
  ```

- Use `parseInt` for Numbers and always with a radix for type casting.
- If for whatever reason you are doing something wild and `parseInt` is your bottleneck and need to use Bitshift for [performance reasons](http://jsperf.com/coercion-vs-casting/3), leave a comment explaining why and what you're doing.

  ```javascript
  var inputValue = '4';

  // bad
  var val = new Number(inputValue);

  // bad
  var val = +inputValue;

  // bad
  var val = inputValue >> 0;

  // bad
  var val = parseInt(inputValue);

  // good
  var val = Number(inputValue);

  // good
  var val = parseInt(inputValue, 10);

  // good
  /**
   * parseInt was the reason my code was slow.
   * Bitshifting the String to coerce it to a
   * Number made it a lot faster.
   */
  var val = inputValue >> 0;
  ```

- Booleans:

  ```javascript
  var age = 0;

  // bad
  var hasAge = new Boolean(age);

  // good
  var hasAge = Boolean(age);

  // good
  var hasAge = !!age;
  ```

  **[[⬆]](#TOC)**


## <a name='naming-conventions'>Naming Conventions</a>
- Name variables and functions logically: For example: `popUpWindowForAd` rather than `myWindow`.

- All Boolean variables should start with "is".
  ```javascript
  isValid = (test.value >= 4 && test.success);
  ```

- Avoid single letter names. Be descriptive with your naming.

  ```javascript
  // bad
  function q () {
    // ...stuff...
  }

  // good
  function query () {
    // ..stuff..
  }
  ```

- Use camelCase when naming objects, functions, and instances

  ```javascript
  // bad
  var OBJEcttsssss = {};
  var this_is_my_object = {};
  var this-is-my-object = {};
  function c() {};
  var u = new user({
    name: 'Bob Parr'
  });

  // good
  var thisIsMyObject = {};
  function thisIsMyFunction() {};
  var user = new User({
    name: 'Bob Parr'
  });
  ```

- Use PascalCase when naming constructors or classes

  ```javascript
  // bad
  function user(options) {
    this.name = options.name;
  }

  var bad = new user({
    name: 'nope'
  });

  // good
  function User(options) {
    this.name = options.name;
  }

  var good = new User({
    name: 'yup'
  });
  ```

- Use a leading underscore `_` when naming private properties

  ```javascript
  // bad
  this.__firstName__ = 'Panda';
  this.firstName_ = 'Panda';

  // good
  this._firstName = 'Panda';
  ```

- When saving a reference to `this` use `_this`.

  ```javascript
  // bad
  function () {
    var self = this;
    return function() {
      console.log(self);
    };
  }

  // bad
  function () {
    var that = this;
    return function() {
      console.log(that);
    };
  }

  // good
  function () {
    var _this = this;
    return function() {
      console.log(_this);
    };
  }
  ```

- Name your functions. This is helpful for stack traces.

  ```javascript
  // bad
  var log = function (msg) {
    console.log(msg);
  };

  // good
  var log = function log (msg) {
    console.log(msg);
  };
  ```

- Constant values

  If a value is intended to be constant and immutable, it should be given a name in `CONSTANT_VALUE_CASE`. `ALL_CAPS` additionally implies `@const` (that the value is not overwritable).

  Primitive types (number, string, boolean) are constant values.

  Objects' immutabilty is more subjective — objects should be considered immutable only if they do not demonstrate obeserverable state change. This is not enforced by the compiler.

- Constant pointers (variables and properties)

  The `@const` annotation on a variable or property implies that it is not overwritable. This is enforced by the compiler at build time. This behavior is consistent with the const keyword (which we do not use due to the lack of support in Internet Explorer).

  A `@const` annotation on a method additionally implies that the method should not be overriden in subclasses.

  **Examples**

  Note that `@const` does not necessarily imply `CONSTANT_VALUES_CASE`. However, `CONSTANT_VALUES_CASE` does imply `@const`.

  ```javascript
  /**
   * Request timeout in milliseconds.
   * @type {number}
   */
  goog.example.TIMEOUT_IN_MILLISECONDS = 60;
  ```

  The number of seconds in a minute never changes. It is a constant value. `ALL_CAPS` also implies `@const`, so the constant cannot be overwritten.

  The open source compiler will allow the symbol it to be overwritten because the constant is not marked as `@const`.

  ```javascript
  /**
   * Map of URL to response string.
   * @const
   */
  MyClass._fetchedUrlCache = new goog.structs.Map();
  ```

  In this case, the pointer can never be overwritten, but value is highly mutable and not constant (and thus in `camelCase`, not `ALL_CAPS`).


  **[[⬆]](#TOC)**


## <a name='accessors'>Accessors</a>

- Accessor functions for properties are not required
- If you do make accessor functions use `getVal()` and `setVal('hello')`

  ```javascript
  // bad
  dragon.age();

  // good
  dragon.getAge();

  // bad
  dragon.age(25);

  // good
  dragon.setAge(25);
  ```

- If the property is a boolean, use `isVal()` or `hasVal()`

  ```javascript
  // bad
  if (!dragon.age()) {
    return false;
  }

  // good
  if (!dragon.hasAge()) {
    return false;
  }
  ```

- It's okay to create `get()` and `set()` functions, but be consistent.

  ```javascript
  function Jedi (options) {
    options || (options = {});
    var lightsaber = options.lightsaber || 'blue';
    this.set('lightsaber', lightsaber);
  }

  Jedi.prototype.set = function (key, val) {
    this[key] = val;
  };

  Jedi.prototype.get = function (key) {
    return this[key];
  };
  ```

  **[[⬆]](#TOC)**


## <a name='constructors'>Constructors</a>

- Assign methods to the prototype object, instead of overwriting the prototype with a new object. Overwriting the prototype makes inheritance impossible: by resetting the prototype you'll overwrite the base!

  ```javascript
  function Jedi () {
    console.log('new jedi');
  }

  // bad
  Jedi.prototype = {
    fight: function fight () {
      console.log('fighting');
    },

    block: function block () {
      console.log('blocking');
    }
  };

  // good
  Jedi.prototype.fight = function fight () {
    console.log('fighting');
  };

  Jedi.prototype.block = function block () {
    console.log('blocking');
  };
  ```

- Methods can return `this` to help with method chaining.

  ```javascript
  // bad
  Jedi.prototype.jump = function () {
    this.jumping = true;
    return true;
  };

  Jedi.prototype.setHeight = function (height) {
    this.height = height;
  };

  var luke = new Jedi();
  luke.jump(); // => true
  luke.setHeight(20) // => undefined

  // good
  Jedi.prototype.jump = function () {
    this.jumping = true;
    return this;
  };

  Jedi.prototype.setHeight = function (height) {
    this.height = height;
    return this;
  };

  var luke = new Jedi();

  luke.jump()
    .setHeight(20);
  ```


- It's okay to write a custom `toString()` method, just make sure it works successfully and causes no side effects.

  ```javascript
  function Jedi (options) {
    options || (options = {});
    this.name = options.name || 'no name';
  }

  Jedi.prototype.getName = function getName () {
    return this.name;
  };

  Jedi.prototype.toString = function toString () {
    return 'Jedi - ' + this.getName();
  };
  ```

  **[[⬆]](#TOC)**


## <a name='modules'>Modules</a>

- The module should start with a `!`. This ensures that if a malformed module forgets to include a final semicolon there aren't errors in production when the scripts get concatenated.
- The file should be named with camelCase, live in a folder with the same name, and match the name of the single export.
- Add a method called `noConflict()` that sets the exported module to the previous version and returns this one.
- Always declare `'use strict';` at the top of the module.

  ```javascript
  // fancyInput/fancyInput.js

  !function(global) {
    'use strict';

    var previousFancyInput = global.FancyInput;

    function FancyInput (options) {
      this.options = options || {};
    }

    FancyInput.noConflict = function noConflict () {
      global.FancyInput = previousFancyInput;
      return FancyInput;
    };

    global.FancyInput = FancyInput;
  }(this);
  ```

  **[[⬆]](#TOC)**


## <a name='jquery'>jQuery</a>

- Prefix jQuery object variables with a `$`.

  ```javascript
  // bad
  var sidebar = $('.sidebar');

  // good
  var $sidebar = $('.sidebar');
  ```

- Cache jQuery lookups.

  ```javascript
  // bad
  function setSidebar () {
    $('.sidebar').hide();

    // ...stuff...

    $('.sidebar').css({
      'background-color': 'pink'
    });
  }

  // good
  function setSidebar () {
    var $sidebar = $('.sidebar');
    $sidebar.hide();

    // ...stuff...

    $sidebar.css({
      'background-color': 'pink'
    });
  }
  ```

- For DOM queries use Cascading `$('.sidebar ul')` or parent > child `$('.sidebar > ul')`. [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16)
- Use `find` with scoped jQuery object queries.

  ```javascript
  // bad
  $('.sidebar', 'ul').hide();

  // bad
  $('.sidebar').find('ul').hide();

  // good
  $('.sidebar ul').hide();

  // good
  $('.sidebar > ul').hide();

  // good (slower)
  $sidebar.find('ul');

  // good (faster)
  $($sidebar[0]).find('ul');
  ```

**[[⬆]](#TOC)**


## <a name='es5'>ECMAScript 5 Compatibility</a>

- Refer to [Kangax](https://twitter.com/kangax/)'s ES5 [compatibility table](http://kangax.github.com/es5-compat-table/)

**[[⬆]](#TOC)**


## <a name='testing'>Testing</a>

- **Yup.**

  ```javascript
  function () {
    return true;
  }
  ```

**[[⬆]](#TOC)**


## <a name='performance'>Performance</a>

 - Prefer `this.foo = null`.

  ```javascript
  Foo.prototype.dispose = function dispose () {
    this.property_ = null;
  };
  ```

  Instead of:

  ```javascript
  Foo.prototype.dispose = function dispose () {
    delete this.property_;
  };
  ```
  In modern JavaScript engines, changing the number of properties on an object is much slower than reassigning the values. The delete keyword should be avoided except when it is necessary to remove a property from an object's iterated list of keys, or to change the result of `if (key in obj)`.


 - Closures

  Yes, but be careful.
  The ability to create closures is perhaps the most useful and often overlooked feature of JS. Here is a good description of how closures work .

  One thing to keep in mind, however, is that a closure keeps a pointer to its enclosing scope. As a result, attaching a closure to a DOM element can create a circular reference and thus, a memory leak. For example, in the following code:

  ```javascript
  function foo (element, a, b) {
    element.onclick = function() { /* uses a and b */ };
  }
  ```

  the function closure keeps a reference to `element`, `a`, and `b` even if it never uses element. Since element also keeps a reference to the closure, we have a cycle that won't be cleaned up by garbage collection. In these situations, the code can be structured as follows:

  ```javascript
  function foo(element, a, b) {
    element.onclick = bar(a, b);
  }

  function bar(a, b) {
    return function() { /* uses a and b */ }
  }
  ```

  * * *
- [On Layout & Web Performance](http://kellegous.com/j/2013/01/26/layout-performance/)
- [String vs Array Concat](http://jsperf.com/string-vs-array-concat/2)
- [Try/Catch Cost In a Loop](http://jsperf.com/try-catch-in-loop-cost)
- [Bang Function](http://jsperf.com/bang-function)
- [jQuery Find vs Context, Selector](http://jsperf.com/jquery-find-vs-context-sel/13)
- [innerHTML vs textContent for script text](http://jsperf.com/innerhtml-vs-textcontent-for-script-text)
- [Long String Concatenation](http://jsperf.com/ya-string-concat)
- Loading...

**[[⬆]](#TOC)**


## <a name='resources'>Resources</a>


**Read This**

- [Annotated ECMAScript 5.1](http://es5.github.com/)

**Other Styleguides**

- [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml)
- [jQuery Core Style Guidelines](http://docs.jquery.com/JQuery_Core_Style_Guidelines)
- [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwldrn/idiomatic.js/)

**Other Styles**

- [Naming this in nested functions](https://gist.github.com/4135065) - Christian Johansen
- [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52)

**Books**

- [JavaScript: The Good Parts](http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742) - Douglas Crockford
- [JavaScript Patterns](http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752) - Stoyan Stefanov
- [Pro JavaScript Design Patterns](http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X)  - Ross Harmes and Dustin Diaz
- [High Performance Web Sites: Essential Knowledge for Front-End Engineers](http://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309) - Steve Souders
- [Maintainable JavaScript](http://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680) - Nicholas C. Zakas
- [JavaScript Web Applications](http://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X) - Alex MacCaw
- [Pro JavaScript Techniques](http://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273) - John Resig
- [Smashing Node.js: JavaScript Everywhere](http://www.amazon.com/Smashing-Node-js-JavaScript-Everywhere-Magazine/dp/1119962595) - Guillermo Rauch

**Blogs**

- [DailyJS](http://dailyjs.com/)
- [JavaScript Weekly](http://javascriptweekly.com/)
- [JavaScript, JavaScript...](http://javascriptweblog.wordpress.com/)
- [Bocoup Weblog](http://weblog.bocoup.com/)
- [Adequately Good](http://www.adequatelygood.com/)
- [NCZOnline](http://www.nczonline.net/)
- [Perfection Kills](http://perfectionkills.com/)
- [Ben Alman](http://benalman.com/)
- [Dmitry Baranovskiy](http://dmitry.baranovskiy.com/)
- [Dustin Diaz](http://dustindiaz.com/)
- [nettuts](http://net.tutsplus.com/?s=javascript)

**[[⬆]](#TOC)**


## <a name='license'>License</a>

(The MIT License)

Copyright (c) 2012 Airbnb

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

**[[⬆]](#TOC)**

# };