|
7 | 7 | 1. [General Coding Principles](#general-coding-principles) |
8 | 8 | 1. [Types](#types) |
9 | 9 | 1. [Objects](#objects) |
| 10 | + 1. [OOP](#oop) |
10 | 11 | 1. [Arrays](#arrays) |
11 | 12 | 1. [Strings](#strings) |
12 | 13 | 1. [Functions](#functions) |
|
46 | 47 |
|
47 | 48 | - Don't use document.write(). |
48 | 49 |
|
49 | | - - Definition order |
50 | | - |
51 | | - ```javascript |
52 | | - var object = function () { |
53 | | - //private variables |
54 | | - //public variables |
55 | | - //private functions |
56 | | - //public functions |
57 | | - } |
58 | | - ``` |
59 | | - |
60 | 50 | - 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. |
61 | 51 |
|
62 | 52 | - Comment your code! It helps reduce time spent troubleshooting JavaScript functions. |
63 | 53 |
|
64 | 54 | - Organize your code as an Object Literal/Singleton, in the Module Pattern, or as an Object with constructors. |
65 | 55 |
|
66 | | - - Minimize global variables - the less globals you create, the better. Generally one, for your application namespace, is a good number. |
| 56 | + - Minimize global variables - the less globals you create, the better. Generally one, for your application namespace, is a good number: |
67 | 57 |
|
68 | 58 | ```javascript |
69 | 59 | window.globalVar = { ... } |
70 | 60 | ``` |
71 | 61 |
|
72 | | - **[[⬆]](#TOC)** |
| 62 | + - 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). |
| 63 | + |
| 64 | + - Explicit scope |
| 65 | + 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. |
| 66 | + |
| 67 | + **[[⬆]](#TOC)** |
| 68 | +
|
73 | 69 |
|
74 | 70 | ## <a name='types'>Types</a> |
75 | 71 |
|
76 | 72 | - **Primitives**: When you access a primitive type you work directly on its value |
77 | 73 |
|
78 | | - + `string` |
79 | | - + `number` |
80 | | - + `boolean` |
81 | | - + `null` |
82 | | - + `undefined` |
| 74 | + * `string` |
| 75 | + * `number` |
| 76 | + * `boolean` |
| 77 | + * `null` |
| 78 | + * `undefined` |
83 | 79 |
|
84 | 80 | ```javascript |
85 | 81 | var foo = 1, |
86 | 82 | bar = foo; |
87 | | - |
88 | 83 | bar = 9; |
89 | | - |
90 | 84 | console.log(foo, bar); // => 1, 9 |
91 | 85 | ``` |
92 | 86 | - **Complex**: When you access a complex type you work on a reference to its value |
|
121 | 115 | + **Local Variables:** `variable === undefined` |
122 | 116 | + **Properties:** `object.prop === undefined` |
123 | 117 |
|
124 | | - **[[⬆]](#TOC)** |
| 118 | + **[[⬆]](#TOC)** |
125 | 119 |
|
126 | 120 | ## <a name='objects'>Objects</a> |
127 | 121 |
|
|
154 | 148 | ``` |
155 | 149 | **[[⬆]](#TOC)** |
156 | 150 |
|
| 151 | +## <a name='oop'>OOP</a> |
| 152 | + |
| 153 | + - Definition order |
| 154 | + |
| 155 | + ```javascript |
| 156 | + var object = function () { |
| 157 | + //private variables |
| 158 | + //public variables |
| 159 | + //private functions |
| 160 | + //public functions |
| 161 | + } |
| 162 | + ``` |
| 163 | + - Method and property definitions: |
| 164 | + |
| 165 | + ```javascript |
| 166 | + /** @constructor */ |
| 167 | + function SomeConstructor() { |
| 168 | + this.someProperty = 1; |
| 169 | + } |
| 170 | + Foo.prototype.someMethod = function() { ... }; |
| 171 | + ``` |
| 172 | + |
| 173 | + While there are several ways to attach methods and properties to an object created via "new", the preferred style for methods is: |
| 174 | + |
| 175 | + ```javascript |
| 176 | + Foo.prototype.bar = function() { |
| 177 | + /* ... */ |
| 178 | + }; |
| 179 | + ``` |
| 180 | + |
| 181 | + The preferred style for other properties is to initialize the field in the constructor: |
| 182 | + |
| 183 | + ```javascript |
| 184 | + /** @constructor */ |
| 185 | + function Foo() { |
| 186 | + this.bar = value; |
| 187 | + } |
| 188 | + ``` |
| 189 | + |
| 190 | + - Modifying prototypes of builtin objects: |
| 191 | + 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. |
| 192 | +
|
| 193 | + - Custom toString() methods |
| 194 | + Must always succeed without side effects. |
| 195 | +
|
| 196 | + 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()`. |
| 197 | +
|
| 198 | + **[[⬆]](#TOC)** |
| 199 | +
|
157 | 200 | ## <a name='arrays'>Arrays</a> |
158 | 201 |
|
159 | 202 | - Use the literal syntax for array creation |
|
1184 | 1227 | }; |
1185 | 1228 | ``` |
1186 | 1229 |
|
| 1230 | + - Constant values |
| 1231 | +
|
| 1232 | + 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). |
| 1233 | +
|
| 1234 | + Primitive types (number, string, boolean) are constant values. |
| 1235 | +
|
| 1236 | + 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. |
| 1237 | +
|
| 1238 | + - Constant pointers (variables and properties) |
| 1239 | +
|
| 1240 | + 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). |
| 1241 | +
|
| 1242 | + A @const annotation on a method additionally implies that the method should not be overriden in subclasses. |
| 1243 | +
|
| 1244 | + **Examples** |
| 1245 | +
|
| 1246 | + Note that @const does not necessarily imply `CONSTANT_VALUES_CASE`. However, `CONSTANT_VALUES_CASE` does imply @const. |
| 1247 | +
|
| 1248 | + ```javascript |
| 1249 | + /** |
| 1250 | + * Request timeout in milliseconds. |
| 1251 | + * @type {number} |
| 1252 | + */ |
| 1253 | + goog.example.TIMEOUT_IN_MILLISECONDS = 60; |
| 1254 | + ``` |
| 1255 | +
|
| 1256 | + 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. |
| 1257 | +
|
| 1258 | + The open source compiler will allow the symbol it to be overwritten because the constant is not marked as @const. |
| 1259 | +
|
| 1260 | + ```javascript |
| 1261 | + /** |
| 1262 | + * Map of URL to response string. |
| 1263 | + * @const |
| 1264 | + */ |
| 1265 | + MyClass.fetchedUrlCache_ = new goog.structs.Map(); |
| 1266 | + ``` |
| 1267 | +
|
| 1268 | + In this case, the pointer can never be overwritten, but value is highly mutable and not constant (and thus in `camelCase`, not `ALL_CAPS`). |
| 1269 | +
|
| 1270 | +
|
1187 | 1271 | **[[⬆]](#TOC)** |
1188 | 1272 |
|
1189 | 1273 |
|
|
1419 | 1503 | $($sidebar[0]).find('ul'); |
1420 | 1504 | ``` |
1421 | 1505 |
|
1422 | | - **[[⬆]](#TOC)** |
| 1506 | + **[[⬆]](#TOC)** |
1423 | 1507 |
|
1424 | 1508 |
|
1425 | 1509 | ## <a name='es5'>ECMAScript 5 Compatibility</a> |
|
1439 | 1523 | } |
1440 | 1524 | ``` |
1441 | 1525 |
|
1442 | | - **[[⬆]](#TOC)** |
| 1526 | + **[[⬆]](#TOC)** |
1443 | 1527 |
|
1444 | 1528 |
|
1445 | 1529 | ## <a name='performance'>Performance</a> |
1446 | 1530 |
|
| 1531 | + - Prefer `this.foo = null`. |
| 1532 | +
|
| 1533 | + ```javascript |
| 1534 | + Foo.prototype.dispose = function() { |
| 1535 | + this.property_ = null; |
| 1536 | + }; |
| 1537 | + ``` |
| 1538 | +
|
| 1539 | + Instead of: |
| 1540 | +
|
| 1541 | + ```javascript |
| 1542 | + Foo.prototype.dispose = function() { |
| 1543 | + delete this.property_; |
| 1544 | + }; |
| 1545 | + ``` |
| 1546 | + 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)`. |
| 1547 | +
|
| 1548 | +
|
| 1549 | + - Closures |
| 1550 | +
|
| 1551 | + Yes, but be careful. |
| 1552 | + 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 . |
| 1553 | +
|
| 1554 | + 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: |
| 1555 | +
|
| 1556 | + ```javascript |
| 1557 | + function foo(element, a, b) { |
| 1558 | + element.onclick = function() { /* uses a and b */ }; |
| 1559 | + } |
| 1560 | + ``` |
| 1561 | +
|
| 1562 | + 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: |
| 1563 | +
|
| 1564 | + ```javascript |
| 1565 | + function foo(element, a, b) { |
| 1566 | + element.onclick = bar(a, b); |
| 1567 | + } |
| 1568 | + |
| 1569 | + function bar(a, b) { |
| 1570 | + return function() { /* uses a and b */ } |
| 1571 | + } |
| 1572 | + ``` |
| 1573 | +
|
| 1574 | + * * * |
1447 | 1575 | - [On Layout & Web Performance](http://kellegous.com/j/2013/01/26/layout-performance/) |
1448 | 1576 | - [String vs Array Concat](http://jsperf.com/string-vs-array-concat/2) |
1449 | 1577 | - [Try/Catch Cost In a Loop](http://jsperf.com/try-catch-in-loop-cost) |
|
0 commit comments