From 29c6efad9a0ccb964e9375ba15f62f644cae10b6 Mon Sep 17 00:00:00 2001 From: Dmitry Vasyuta Date: Wed, 27 Mar 2013 13:38:09 +0200 Subject: [PATCH 01/15] Merge with jquery, isobar and logiceditor.com --- README.md | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 155 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d5525cb9f1..8b731e99c9 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ## Table of Contents - + 1. [General Coding Principles](#general-coding-principles) 1. [Types](#types) 1. [Objects](#objects) 1. [Arrays](#arrays) @@ -35,6 +35,42 @@ 1. [Contributors](#contributors) 1. [License](#license) + + + +## General Coding Principles + + - 99% of code should be housed in external javascript files. They should be included at the END of the BODY tag for maximum page performance. + + - Don't rely on the user-agent string. Do proper feature detection. (More at Dive Into HTML5: Detection & jQuery.support docs) + + - Don't use document.write(). + + - Definition order + + ```javascript + var object = function () { + //private variables + //public variables + //private functions + //public functions + } + ``` + + - Strive to create functions which can be generalized, take parameters, and return values. This allows for substantial code reuse and, when combined with includes or external scripts, can reduce the overhead when scripts need to change. For example, instead of hard coding a pop-window with window size, options, and url, consider creating a function which takes size, url, and options as variables. + + - Comment your code! It helps reduce time spent troubleshooting JavaScript functions. + + - Organize your code as an Object Literal/Singleton, in the Module Pattern, or as an Object with constructors. + + - Minimize global variables - the less globals you create, the better. Generally one, for your application namespace, is a good number. + + ```javascript + window.globalVar = { ... } + ``` + + **[[⬆]](#TOC)** + ## Types - **Primitives**: When you access a primitive type you work directly on its value @@ -68,6 +104,25 @@ console.log(foo[0], bar[0]); // => 9, 9 ``` + - Type Checks + + ```javascript + + **String:** `typeof object === "string"` + + **Number:** `typeof object === "number"` + + **Boolean:** `typeof object === "boolean"` + + **Object:** `typeof object === "object"` + + **Plain Object:** `jQuery.isPlainObject(object)` + + **Function:** `jQuery.isFunction(object)` + + **Array:** `jQuery.isArray(object)` + + **Element:** `object.nodeType` + + **null:** `object === null` + + **null or undefined:** `object == null` + + **undefined:** + + **Global Variables:** `typeof variable === "undefined"` + + **Local Variables:** `variable === undefined` + + **Properties:** `object.prop === undefined` + ``` + **[[⬆]](#TOC)** ## Objects @@ -698,12 +753,12 @@ ## Whitespace - + - Use soft tabs set to 2 spaces ```javascript // bad - function() { + function∙() { ∙∙∙∙var name; } @@ -713,10 +768,99 @@ } // good - function() { + 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'; + ``` + + - if/else/for/while/try/function always have braces, one space around parentheses and always go on multiple lines. + + ```javascript + // Bad + if( condition ) doSomething(); + + // Bad + while( condition ) iterating++; + + // Bad + for( var i=0;i<100;i++ ) someIterativeFn(); + + // Bad + object[array[0]]; + + + // Good + if (condition) { + // expressions + } + + // Good + while (condition) { + // expressions + } + + // Good + var i = 0; + + for (; i < 100; i++) { + // expressions + } + + // Good + var prop; + + for (prop in object) { + // expressions + } + + // Good + if (condition) { + // expressions + } else { + // expressions + } + + // Good + if (condition) { + // expressions + } else if (condition) { + // expressions + } else { + // expressions + } + + // Good + try { + // expressions + } catch (e) { + // expressions + } + + // Good + try { + // expressions + } catch (e) { + // expressions + } finally { + // expressions + } + + // Good + object[array[ 0 ]]; + ``` + - Place 1 space before the leading brace. ```javascript @@ -737,7 +881,7 @@ }); // good - dog.set('attr', { + dog.set('attr',.{ age: '1 year', breed: 'Bernese Mountain Dog' }); @@ -855,7 +999,6 @@ ## Type Casting & Coercion - - Perform type coercion at the beginning of the statement. - Strings: @@ -927,6 +1070,12 @@ ## Naming Conventions + - 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. From 8b94609edc78679258504206fb062b1cc5ca7c01 Mon Sep 17 00:00:00 2001 From: Dmitry Vasyuta Date: Wed, 27 Mar 2013 13:40:19 +0200 Subject: [PATCH 02/15] Fix type checks section --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 8b731e99c9..47cd54c955 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,6 @@ - Type Checks - ```javascript + **String:** `typeof object === "string"` + **Number:** `typeof object === "number"` + **Boolean:** `typeof object === "boolean"` @@ -121,7 +120,6 @@ + **Global Variables:** `typeof variable === "undefined"` + **Local Variables:** `variable === undefined` + **Properties:** `object.prop === undefined` - ``` **[[⬆]](#TOC)** From 2ddbc7976a52c0c1d1d6c55450ebcc19a81a6c8b Mon Sep 17 00:00:00 2001 From: Dmitry Vasyuta Date: Thu, 28 Mar 2013 13:15:25 +0200 Subject: [PATCH 03/15] Merge with Google --- README.md | 174 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 151 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 47cd54c955..3a6345b4e1 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ 1. [General Coding Principles](#general-coding-principles) 1. [Types](#types) 1. [Objects](#objects) + 1. [OOP](#oop) 1. [Arrays](#arrays) 1. [Strings](#strings) 1. [Functions](#functions) @@ -46,47 +47,40 @@ - Don't use document.write(). - - Definition order - - ```javascript - var object = function () { - //private variables - //public variables - //private functions - //public functions - } - ``` - - Strive to create functions which can be generalized, take parameters, and return values. This allows for substantial code reuse and, when combined with includes or external scripts, can reduce the overhead when scripts need to change. For example, instead of hard coding a pop-window with window size, options, and url, consider creating a function which takes size, url, and options as variables. - Comment your code! It helps reduce time spent troubleshooting JavaScript functions. - Organize your code as an Object Literal/Singleton, in the Module Pattern, or as an Object with constructors. - - Minimize global variables - the less globals you create, the better. Generally one, for your application namespace, is a good number. + - Minimize global variables - the less globals you create, the better. Generally one, for your application namespace, is a good number: ```javascript window.globalVar = { ... } ``` - **[[⬆]](#TOC)** + - For maximum portability and compatibility, always prefer standards features over non-standards features (e.g., `string.charAt(3)` over `string[3] ` and element access with DOM functions instead of using an application-specific shorthand). + + - Explicit scope + Always use explicit scope - doing so increases portability and clarity. For example, don't rely on window being in the scope chain. You might want to use your function in another application for which window is not the content window. + + **[[⬆]](#TOC)** + ## Types - **Primitives**: When you access a primitive type you work directly on its value - + `string` - + `number` - + `boolean` - + `null` - + `undefined` + * `string` + * `number` + * `boolean` + * `null` + * `undefined` ```javascript var foo = 1, bar = foo; - bar = 9; - console.log(foo, bar); // => 1, 9 ``` - **Complex**: When you access a complex type you work on a reference to its value @@ -121,7 +115,7 @@ + **Local Variables:** `variable === undefined` + **Properties:** `object.prop === undefined` - **[[⬆]](#TOC)** + **[[⬆]](#TOC)** ## Objects @@ -154,6 +148,55 @@ ``` **[[⬆]](#TOC)** +## OOP + + - Definition order + + ```javascript + var object = function () { + //private variables + //public variables + //private functions + //public functions + } + ``` + - Method and property definitions: + + ```javascript + /** @constructor */ + function SomeConstructor() { + this.someProperty = 1; + } + Foo.prototype.someMethod = function() { ... }; + ``` + + While there are several ways to attach methods and properties to an object created via "new", the preferred style for methods is: + + ```javascript + Foo.prototype.bar = function() { + /* ... */ + }; + ``` + + The preferred style for other properties is to initialize the field in the constructor: + + ```javascript + /** @constructor */ + function Foo() { + this.bar = value; + } + ``` + + - Modifying prototypes of builtin objects: + Modifying builtins like `Object.prototype` and `Array.prototype` are strictly forbidden. Modifying other builtins like `Function.prototype` is less dangerous but still leads to hard to debug issues in production and should be avoided. + + - Custom toString() methods + Must always succeed without side effects. + + You can control how your objects string-ify themselves by defining a custom `toString()` method. This is fine, but you need to ensure that your method (1) always succeeds and (2) does not have side-effects.If your method doesn't meet these criteria, it's very easy to run into serious problems. For example, if `toString()` calls a method that does an assert, assert might try to output the name of the object in which it failed, which of course requires calling `toString()`. + + **[[⬆]](#TOC)** + ## Arrays - Use the literal syntax for array creation @@ -1184,6 +1227,47 @@ }; ``` + - 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)** @@ -1419,7 +1503,7 @@ $($sidebar[0]).find('ul'); ``` - **[[⬆]](#TOC)** + **[[⬆]](#TOC)** ## ECMAScript 5 Compatibility @@ -1439,11 +1523,55 @@ } ``` - **[[⬆]](#TOC)** + **[[⬆]](#TOC)** ## Performance + - Prefer `this.foo = null`. + + ```javascript + Foo.prototype.dispose = function() { + this.property_ = null; + }; + ``` + + Instead of: + + ```javascript + Foo.prototype.dispose = function() { + 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) From e8029c5588f1ecdbbb3a4aff2836ae3104291bc7 Mon Sep 17 00:00:00 2001 From: Dmitry Vasyuta Date: Thu, 28 Mar 2013 13:27:32 +0200 Subject: [PATCH 04/15] Structure changing --- README.md | 40 ++-------------------------------------- 1 file changed, 2 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 3a6345b4e1..f2cd04ea22 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Airbnb JavaScript Style Guide() { +# JavaScript Style Guide() { *A mostly reasonable approach to JavaScript* @@ -30,10 +30,6 @@ 1. [Testing](#testing) 1. [Performance](#performance) 1. [Resources](#resources) - 1. [In the Wild](#in-the-wild) - 1. [Translation](#translation) - 1. [The JavaScript Style Guide Guide](#guide-guide) - 1. [Contributors](#contributors) 1. [License](#license) @@ -63,7 +59,7 @@ - Explicit scope Always use explicit scope - doing so increases portability and clarity. For example, don't rely on window being in the scope chain. You might want to use your function in another application for which window is not the content window. - + **[[⬆]](#TOC)** @@ -1629,38 +1625,6 @@ **[[⬆]](#TOC)** -## In the Wild - - This is a list of organizations that are using this style guide. Send us a pull request or open an issue and we'll add you to the list. - - - **Airbnb**: [airbnb/javascript](https://github.com/airbnb/javascript) - - **American Insitutes for Research**: [AIRAST/javascript](https://github.com/AIRAST/javascript) - - **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript) - - **GoodData**: [gooddata/gdc-js-style](https://github.com/gooddata/gdc-js-style) - - **How About We**: [howaboutwe/javascript](https://github.com/howaboutwe/javascript) - - **MinnPost**: [MinnPost/javascript](https://github.com/MinnPost/javascript) - - **ModCloth**: [modcloth/javascript](https://github.com/modcloth/javascript) - - **National Geographic**: [natgeo/javascript](https://github.com/natgeo/javascript) - - **Razorfish**: [razorfish/javascript-style-guide](https://github.com/razorfish/javascript-style-guide) - - **Shutterfly**: [shutterfly/javascript](https://github.com/shutterfly/javascript) - - **Userify**: [userify/javascript](https://github.com/userify/javascript) - - **Zillow**: [zillow/javascript](https://github.com/zillow/javascript) - -## Translation - - This style guide is also available in other languages: - - - :de: **German**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide) - - :jp: **Japanese**: [mitsuruog/javacript-style-guide](https://github.com/mitsuruog/javacript-style-guide) - -## The JavaScript Style Guide Guide - - - [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide) - -## Contributors - - - [View Contributors](https://github.com/airbnb/javascript/graphs/contributors) - ## License From f4072ab78dbc7c4f580c630f7aba1a39e31a0c2f Mon Sep 17 00:00:00 2001 From: Dmitry Vasyuta Date: Thu, 28 Mar 2013 14:38:25 +0200 Subject: [PATCH 05/15] Duplicate removed --- README.md | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/README.md b/README.md index f2cd04ea22..8b2a5983ab 100644 --- a/README.md +++ b/README.md @@ -1385,24 +1385,6 @@ .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)** From 4aee878c4a10f7b52c7386ff7724e45227784cd1 Mon Sep 17 00:00:00 2001 From: Dmitry Mina Date: Fri, 29 Mar 2013 11:55:35 +0200 Subject: [PATCH 06/15] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8b2a5983ab..4b590c1e47 100644 --- a/README.md +++ b/README.md @@ -205,7 +205,7 @@ var items = []; ``` - - If you don't know array length use Array#push. + - If you don't know array length use `Array#push`. ```javascript var someStack = []; From c2184f35db326672087d6ad0e385d7a546067b17 Mon Sep 17 00:00:00 2001 From: Dmitry Vasyuta Date: Fri, 29 Mar 2013 12:09:03 +0200 Subject: [PATCH 07/15] Text corrections --- README.md | 337 ++++++++++++++++++++++++++---------------------------- 1 file changed, 164 insertions(+), 173 deletions(-) diff --git a/README.md b/README.md index 4b590c1e47..bd5ef67730 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ ## General Coding Principles - + - 99% of code should be housed in external javascript files. They should be included at the END of the BODY tag for maximum page performance. - Don't rely on the user-agent string. Do proper feature detection. (More at Dive Into HTML5: Detection & jQuery.support docs) @@ -44,21 +44,20 @@ - Don't use document.write(). - Strive to create functions which can be generalized, take parameters, and return values. This allows for substantial code reuse and, when combined with includes or external scripts, can reduce the overhead when scripts need to change. For example, instead of hard coding a pop-window with window size, options, and url, consider creating a function which takes size, url, and options as variables. - + - Comment your code! It helps reduce time spent troubleshooting JavaScript functions. - - Organize your code as an Object Literal/Singleton, in the Module Pattern, or as an Object with constructors. + - Organize your code as an [Object Literal/Singleton](http://kaijaeger.com/articles/the-singleton-design-pattern-in-javascript.html), in the [Module Pattern](http://www.yuiblog.com/blog/2007/06/12/module-pattern/), or as an [Object with constructors](http://mckoss.com/jscript/object.htm). - Minimize global variables - the less globals you create, the better. Generally one, for your application namespace, is a good number: ```javascript window.globalVar = { ... } - ``` + ``` - For maximum portability and compatibility, always prefer standards features over non-standards features (e.g., `string.charAt(3)` over `string[3] ` and element access with DOM functions instead of using an application-specific shorthand). - - Explicit scope - Always use explicit scope - doing so increases portability and clarity. For example, don't rely on window being in the scope chain. You might want to use your function in another application for which window is not the content window. + - Always use explicit scope - doing so increases portability and clarity. For example, don't rely on `window` being in the scope chain. You might want to use your function in another application for which `window` is not the content window. **[[⬆]](#TOC)** @@ -164,7 +163,7 @@ this.someProperty = 1; } Foo.prototype.someMethod = function() { ... }; - ``` + ``` While there are several ways to attach methods and properties to an object created via "new", the preferred style for methods is: @@ -172,7 +171,7 @@ Foo.prototype.bar = function() { /* ... */ }; - ``` + ``` The preferred style for other properties is to initialize the field in the constructor: @@ -181,8 +180,8 @@ function Foo() { this.bar = value; } - ``` - + ``` + - Modifying prototypes of builtin objects: Modifying builtins like `Object.prototype` and `Array.prototype` are strictly forbidden. Modifying other builtins like `Function.prototype` is less dangerous but still leads to hard to debug issues in production and should be avoided. @@ -255,8 +254,7 @@ var fullName = 'Bob ' + this.lastName; ``` - - Strings longer than 80 characters should be written across multiple lines using string concatenation. - - Note: If overused, long strings with concatenation could impact performance. [jsPerf](http://jsperf.com/ya-string-concat) & [Discussion](https://github.com/airbnb/javascript/issues/40) + - Strings longer than 80 characters should be written across multiple lines using string concatenation. **Note**: If overused, long strings with concatenation could impact performance. [jsPerf](http://jsperf.com/ya-string-concat) & [Discussion](https://github.com/airbnb/javascript/issues/40) ```javascript // bad @@ -301,7 +299,7 @@ length = messages.length; // bad - function inbox(messages) { + function inbox (messages) { items = '
    '; for (i = 0; i < length; i++) { @@ -312,7 +310,7 @@ } // good - function inbox(messages) { + function inbox (messages) { items = []; for (i = 0; i < length; i++) { @@ -332,35 +330,34 @@ ```javascript // anonymous function expression - var anonymous = function() { + var anonymous = function () { return true; }; // named function expression - var named = function named() { + var named = function named () { return true; }; // immediately-invoked function expression (IIFE) - (function() { + (function () { console.log('Welcome to the Internet. Please follow me.'); })(); ``` - - Never declare a function in a non-function block (if, while, etc). Assign the function to a variable instead. Browsers will allow you to do it, but they all interpret it differently, which is bad news bears. - - **Note:** ECMA-262 defines a `block` as a list of statements. A function declaration is not a statement. [Read ECMA-262's note on this issue](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf#page=97). + - Never declare a function in a non-function block (`if`, `while`, `etc`). Assign the function to a variable instead. Browsers will allow you to do it, but they all interpret it differently, which is bad news bears. **Note:** ECMA-262 defines a `block` as a list of statements. A function declaration is not a statement. [Read ECMA-262's note on this issue](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf#page=97). ```javascript // bad if (currentUser) { - function test() { + function test () { console.log('Nope.'); } } // good if (currentUser) { - var test = function test() { + var test = function test () { console.log('Yup.'); }; } @@ -370,12 +367,12 @@ ```javascript // bad - function nope(name, options, arguments) { + function nope (name, options, arguments) { // ...stuff... } // good - function yup(name, options, args) { + function yup (name, options, args) { // ...stuff... } ``` @@ -409,7 +406,7 @@ age: 28 }; - function getProp(prop) { + function getProp (prop) { return luke[prop]; } @@ -471,7 +468,7 @@ ```javascript // bad - function() { + function () { test(); console.log('doing stuff..'); @@ -487,7 +484,7 @@ } // good - function() { + function () { var name = getName(); test(); @@ -503,7 +500,7 @@ } // bad - function() { + function () { var name = getName(); if (!arguments.length) { @@ -514,7 +511,7 @@ } // good - function() { + function () { if (!arguments.length) { return false; } @@ -535,7 +532,7 @@ ```javascript // we know this wouldn't work (assuming there // is no notDefined global variable) - function example() { + function example () { console.log(notDefined); // => throws a ReferenceError } @@ -543,7 +540,7 @@ // reference the variable will work due to // variable hoisting. Note: the assignment // value of `true` is not hoisted. - function example() { + function example () { console.log(declaredButNotAssigned); // => undefined var declaredButNotAssigned = true; } @@ -551,7 +548,7 @@ // The interpreter is hoisting the variable // declaration to the top of the scope. // Which means our example could be rewritten as: - function example() { + function example () { var declaredButNotAssigned; console.log(declaredButNotAssigned); // => undefined declaredButNotAssigned = true; @@ -561,12 +558,12 @@ - Anonymous function expressions hoist their variable name, but not the function assignment. ```javascript - function example() { + function example () { console.log(anonymous); // => undefined anonymous(); // => TypeError anonymous is not a function - var anonymous = function() { + var anonymous = function () { console.log('anonymous function expression'); }; } @@ -575,26 +572,26 @@ - Named function expressions hoist the variable name, not the function name or the function body. ```javascript - function example() { + function example () { console.log(named); // => undefined named(); // => TypeError named is not a function superPower(); // => ReferenceError superPower is not defined - var named = function superPower() { + var named = function superPower () { console.log('Flying'); }; // the same is true when the function name // is the same as the variable name. - function example() { + function example () { console.log(named); // => undefined named(); // => TypeError named is not a function - var named = function named() { + var named = function named () { console.log('named'); }; } @@ -604,10 +601,10 @@ - Function declarations hoist their name and the function body. ```javascript - function example() { + function example () { superPower(); // => Flying - function superPower() { + function superPower () { console.log('Flying'); } } @@ -669,28 +666,80 @@ ## Blocks - - Use braces with all multi-line blocks. + - if/else/for/while/try/function always have braces, one space around parentheses and always go on multiple lines. ```javascript - // bad - if (test) - return false; + // Bad + if(condition) doSomething(); - // good - if (test) return false; + // Bad + while(condition) iterating++; - // good - if (test) { - return false; + // Bad + for(var i=0;i<100;i++) someIterativeFn(); + + // Bad + object[array[0]]; + + + // Good + if (condition) { + // expressions } - // bad - function() { return false; } + // Good + while (condition) { + // expressions + } - // good - function() { - return false; + // Good + var i = 0; + + for (; i < 100; i++) { + // expressions } + + // Good + var prop; + + for (prop in object) { + // expressions + } + + // Good + if (condition) { + // expressions + } else { + // expressions + } + + // Good + if (condition) { + // expressions + } else if (condition) { + // expressions + } else { + // expressions + } + + // Good + try { + // expressions + } catch (e) { + // expressions + } + + // Good + try { + // expressions + } catch (e) { + // expressions + } finally { + // expressions + } + + // Good + object[array[ 0 ]]; ``` **[[⬆]](#TOC)** @@ -707,7 +756,7 @@ // // @param tag // @return element - function make(tag) { + function make (tag) { // ...stuff... @@ -722,7 +771,7 @@ * @param tag * @return element */ - function make(tag) { + function make (tag) { // ...stuff... @@ -741,7 +790,7 @@ var active = true; // bad - function getType() { + function getType () { console.log('fetching type...'); // set the default type to 'no type' var type = this._type || 'no type'; @@ -750,7 +799,7 @@ } // good - function getType() { + function getType () { console.log('fetching type...'); // set the default type to 'no type' @@ -765,7 +814,7 @@ - Use `// FIXME:` to annotate problems ```javascript - function Calculator() { + function Calculator () { // FIXME: shouldn't use a global here total = 0; @@ -777,7 +826,7 @@ - Use `// TODO:` to annotate solutions to problems ```javascript - function Calculator() { + function Calculator () { // TODO: total should be configurable by an options param this.total = 0; @@ -790,7 +839,7 @@ ## Whitespace - + - Use soft tabs set to 2 spaces ```javascript @@ -811,7 +860,7 @@ ``` - No end of line whitespace. - + - No blank line whitespace. - Place one space before and after binary and ternary operators. @@ -822,82 +871,6 @@ c∙=∙a∙>∙0∙?∙'yes'∙:∙'no'; ``` - - if/else/for/while/try/function always have braces, one space around parentheses and always go on multiple lines. - - ```javascript - // Bad - if( condition ) doSomething(); - - // Bad - while( condition ) iterating++; - - // Bad - for( var i=0;i<100;i++ ) someIterativeFn(); - - // Bad - object[array[0]]; - - - // Good - if (condition) { - // expressions - } - - // Good - while (condition) { - // expressions - } - - // Good - var i = 0; - - for (; i < 100; i++) { - // expressions - } - - // Good - var prop; - - for (prop in object) { - // expressions - } - - // Good - if (condition) { - // expressions - } else { - // expressions - } - - // Good - if (condition) { - // expressions - } else if (condition) { - // expressions - } else { - // expressions - } - - // Good - try { - // expressions - } catch (e) { - // expressions - } - - // Good - try { - // expressions - } catch (e) { - // expressions - } finally { - // expressions - } - - // Good - object[array[ 0 ]]; - ``` - - Place 1 space before the leading brace. ```javascript @@ -907,7 +880,7 @@ } // good - function test() { + function test ()∙{ console.log('test'); } @@ -918,7 +891,7 @@ }); // good - dog.set('attr',.{ + dog.set('attr',∙{ age: '1 year', breed: 'Bernese Mountain Dog' }); @@ -927,14 +900,14 @@ ```javascript // bad - (function(global) { + (function (global) { // ...stuff... })(this); ``` ```javascript // good - (function(global) { + (function (global) { // ...stuff... })(this); @@ -1014,19 +987,19 @@ ```javascript // bad - (function() { + (function () { var name = 'Skywalker' return name })() // good - (function() { + (function () { var name = 'Skywalker'; return name; })(); // good - ;(function() { + ;(function () { var name = 'Skywalker'; return name; })(); @@ -1118,12 +1091,12 @@ ```javascript // bad - function q() { + function q () { // ...stuff... } // good - function query() { + function query () { // ..stuff.. } ``` @@ -1185,7 +1158,7 @@ ```javascript // bad - function() { + function () { var self = this; return function() { console.log(self); @@ -1193,7 +1166,7 @@ } // bad - function() { + function () { var that = this; return function() { console.log(that); @@ -1201,7 +1174,7 @@ } // good - function() { + function () { var _this = this; return function() { console.log(_this); @@ -1213,12 +1186,12 @@ ```javascript // bad - var log = function(msg) { + var log = function (msg) { console.log(msg); }; // good - var log = function log(msg) { + var log = function log (msg) { console.log(msg); }; ``` @@ -1258,7 +1231,7 @@ * Map of URL to response string. * @const */ - MyClass.fetchedUrlCache_ = new goog.structs.Map(); + 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`). @@ -1303,17 +1276,17 @@ - It's okay to create get() and set() functions, but be consistent. ```javascript - function Jedi(options) { + function Jedi (options) { options || (options = {}); var lightsaber = options.lightsaber || 'blue'; this.set('lightsaber', lightsaber); } - Jedi.prototype.set = function(key, val) { + Jedi.prototype.set = function (key, val) { this[key] = val; }; - Jedi.prototype.get = function(key) { + Jedi.prototype.get = function (key) { return this[key]; }; ``` @@ -1326,27 +1299,27 @@ - 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() { + function Jedi () { console.log('new jedi'); } // bad Jedi.prototype = { - fight: function fight() { + fight: function fight () { console.log('fighting'); }, - block: function block() { + block: function block () { console.log('blocking'); } }; // good - Jedi.prototype.fight = function fight() { + Jedi.prototype.fight = function fight () { console.log('fighting'); }; - Jedi.prototype.block = function block() { + Jedi.prototype.block = function block () { console.log('blocking'); }; ``` @@ -1355,12 +1328,12 @@ ```javascript // bad - Jedi.prototype.jump = function() { + Jedi.prototype.jump = function () { this.jumping = true; return true; }; - Jedi.prototype.setHeight = function(height) { + Jedi.prototype.setHeight = function (height) { this.height = height; }; @@ -1369,12 +1342,12 @@ luke.setHeight(20) // => undefined // good - Jedi.prototype.jump = function() { + Jedi.prototype.jump = function () { this.jumping = true; return this; }; - Jedi.prototype.setHeight = function(height) { + Jedi.prototype.setHeight = function (height) { this.height = height; return this; }; @@ -1385,6 +1358,24 @@ .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)** @@ -1403,11 +1394,11 @@ var previousFancyInput = global.FancyInput; - function FancyInput(options) { + function FancyInput (options) { this.options = options || {}; } - FancyInput.noConflict = function noConflict() { + FancyInput.noConflict = function noConflict () { global.FancyInput = previousFancyInput; return FancyInput; }; @@ -1435,7 +1426,7 @@ ```javascript // bad - function setSidebar() { + function setSidebar () { $('.sidebar').hide(); // ...stuff... @@ -1446,7 +1437,7 @@ } // good - function setSidebar() { + function setSidebar () { var $sidebar = $('.sidebar'); $sidebar.hide(); @@ -1496,7 +1487,7 @@ - **Yup.** ```javascript - function() { + function () { return true; } ``` @@ -1509,7 +1500,7 @@ - Prefer `this.foo = null`. ```javascript - Foo.prototype.dispose = function() { + Foo.prototype.dispose = function dispose () { this.property_ = null; }; ``` @@ -1517,7 +1508,7 @@ Instead of: ```javascript - Foo.prototype.dispose = function() { + Foo.prototype.dispose = function dispose () { delete this.property_; }; ``` @@ -1532,7 +1523,7 @@ 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) { + function foo (element, a, b) { element.onclick = function() { /* uses a and b */ }; } ``` @@ -1549,7 +1540,7 @@ } ``` - * * * + * * * - [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) From 1c029305ca88ecdb44a59f56599b97919f3bf3d7 Mon Sep 17 00:00:00 2001 From: Dmitry Mina Date: Fri, 29 Mar 2013 12:23:36 +0200 Subject: [PATCH 08/15] code highlight --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8b2a5983ab..4b590c1e47 100644 --- a/README.md +++ b/README.md @@ -205,7 +205,7 @@ var items = []; ``` - - If you don't know array length use Array#push. + - If you don't know array length use `Array#push`. ```javascript var someStack = []; From 20c3071b12fe32af6cf2059a39af84d58f6fcf8b Mon Sep 17 00:00:00 2001 From: Dmitry Mina Date: Fri, 29 Mar 2013 12:29:27 +0200 Subject: [PATCH 09/15] code highlight --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4b590c1e47..e3f9ef3471 100644 --- a/README.md +++ b/README.md @@ -218,7 +218,7 @@ someStack.push('abracadabra'); ``` - - When you need to copy an array use Array#slice. [jsPerf](http://jsperf.com/converting-arguments-to-an-array/7) + - When you need to copy an array use `Array#slice`. [jsPerf](http://jsperf.com/converting-arguments-to-an-array/7) ```javascript var len = items.length, From 50df4b28f4a37bb61f67d201fe8fe39ad0c0afcf Mon Sep 17 00:00:00 2001 From: Dmitry Mina Date: Fri, 29 Mar 2013 12:35:30 +0200 Subject: [PATCH 10/15] code highlight again --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e3f9ef3471..4423f083b7 100644 --- a/README.md +++ b/README.md @@ -280,7 +280,7 @@ 'fast.'; ``` - - When programatically building up a string, use Array#join instead of string concatenation. Mostly for IE: [jsPerf](http://jsperf.com/string-vs-array-concat/2). + - When programatically building up a string, use `Array#join` instead of string concatenation. Mostly for IE: [jsPerf](http://jsperf.com/string-vs-array-concat/2). ```javascript var items, From 2514d4bdfbef869e8d60a854e3e8613ce863b8fc Mon Sep 17 00:00:00 2001 From: Dmitry Mina Date: Fri, 29 Mar 2013 12:46:23 +0200 Subject: [PATCH 11/15] code highlight again and again --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 4423f083b7..1c3c5d5e30 100644 --- a/README.md +++ b/README.md @@ -1225,7 +1225,7 @@ - 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). + 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. @@ -1233,13 +1233,13 @@ - 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). + 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. + 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. + Note that `@const` does not necessarily imply `CONSTANT_VALUES_CASE`. However, `CONSTANT_VALUES_CASE` does imply `@const`. ```javascript /** @@ -1249,7 +1249,7 @@ 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 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. @@ -1270,7 +1270,7 @@ ## Accessors - Accessor functions for properties are not required - - If you do make accessor functions use getVal() and setVal('hello') + - If you do make accessor functions use `getVal()` and `setVal('hello')` ```javascript // bad @@ -1286,7 +1286,7 @@ dragon.setAge(25); ``` - - If the property is a boolean, use isVal() or hasVal() + - If the property is a boolean, use `isVal()` or `hasVal()` ```javascript // bad @@ -1300,7 +1300,7 @@ } ``` - - It's okay to create get() and set() functions, but be consistent. + - It's okay to create `get()` and `set()` functions, but be consistent. ```javascript function Jedi(options) { @@ -1392,7 +1392,7 @@ - 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. + - 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 From 87c46cc6585ea899ee2ae2c7deab8850668a2ea8 Mon Sep 17 00:00:00 2001 From: Dmitry Mina Date: Fri, 29 Mar 2013 12:57:03 +0200 Subject: [PATCH 12/15] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 55b4997b4f..451798654f 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ - Don't rely on the user-agent string. Do proper feature detection. (More at Dive Into HTML5: Detection & jQuery.support docs) - - Don't use document.write(). + - Don't use `document.write()`. - Strive to create functions which can be generalized, take parameters, and return values. This allows for substantial code reuse and, when combined with includes or external scripts, can reduce the overhead when scripts need to change. For example, instead of hard coding a pop-window with window size, options, and url, consider creating a function which takes size, url, and options as variables. From ef454257373f60cd990095953c7baa97f823ccc3 Mon Sep 17 00:00:00 2001 From: Dmitry Mina Date: Fri, 29 Mar 2013 13:04:19 +0200 Subject: [PATCH 13/15] added some links --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 451798654f..6719e0b7a0 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,8 @@ - 99% of code should be housed in external javascript files. They should be included at the END of the BODY tag for maximum page performance. - - Don't rely on the user-agent string. Do proper feature detection. (More at Dive Into HTML5: Detection & jQuery.support docs) - + - Don't rely on the user-agent string. Do proper feature detection. (More at [Dive Into HTML5: Detection](http://diveintohtml5.info/detect.html) & [jQuery.support docs](http://api.jquery.com/jQuery.support/)) + - Don't use `document.write()`. - Strive to create functions which can be generalized, take parameters, and return values. This allows for substantial code reuse and, when combined with includes or external scripts, can reduce the overhead when scripts need to change. For example, instead of hard coding a pop-window with window size, options, and url, consider creating a function which takes size, url, and options as variables. From 0d150049c6eac6704ef16875a1754d697872811d Mon Sep 17 00:00:00 2001 From: Dmitry Mina Date: Fri, 29 Mar 2013 13:17:20 +0200 Subject: [PATCH 14/15] some code highlight additions --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6719e0b7a0..9eddfbd9a0 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,7 @@ Foo.prototype.someMethod = function() { ... }; ``` - While there are several ways to attach methods and properties to an object created via "new", the preferred style for methods is: + While there are several ways to attach methods and properties to an object created via `new`, the preferred style for methods is: ```javascript Foo.prototype.bar = function() { @@ -1224,7 +1224,7 @@ 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. + The open source compiler will allow the symbol it to be overwritten because the constant is not marked as `@const`. ```javascript /** @@ -1359,7 +1359,7 @@ ``` - - It's okay to write a custom toString() method, just make sure it works successfully and causes no side effects. + - It's okay to write a custom `toString()` method, just make sure it works successfully and causes no side effects. ```javascript function Jedi (options) { @@ -1528,7 +1528,7 @@ } ``` - 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: + 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) { From a8d4b97e59d384980b2f6b7cfcd8068fa573e5db Mon Sep 17 00:00:00 2001 From: Dmitry Mina Date: Sun, 31 Mar 2013 06:57:10 +0300 Subject: [PATCH 15/15] space added --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9eddfbd9a0..9871693f94 100644 --- a/README.md +++ b/README.md @@ -188,7 +188,7 @@ - Custom toString() methods Must always succeed without side effects. - You can control how your objects string-ify themselves by defining a custom `toString()` method. This is fine, but you need to ensure that your method (1) always succeeds and (2) does not have side-effects.If your method doesn't meet these criteria, it's very easy to run into serious problems. For example, if `toString()` calls a method that does an assert, assert might try to output the name of the object in which it failed, which of course requires calling `toString()`. + You can control how your objects string-ify themselves by defining a custom `toString()` method. This is fine, but you need to ensure that your method (1) always succeeds and (2) does not have side-effects. If your method doesn't meet these criteria, it's very easy to run into serious problems. For example, if `toString()` calls a method that does an assert, assert might try to output the name of the object in which it failed, which of course requires calling `toString()`. **[[⬆]](#TOC)**