| 31 | | * Consider using [http://people.mozilla.org/~jorendorff/es6-draft.html#sec-keyed-collection `Map` and `Set` collections] instead of plain objects. |
| 32 | | * Consider using `hsla()' over hex or RGB colors in CSS. |
| 33 | | * Use `for..of` syntax when performing small actions on each element. Use `forEach` when the function body is longer. Use a classical for loop when doing index math. |
| | 27 | * Use [http://people.mozilla.org/~jorendorff/es6-draft.html#sec-keyed-collection `Map` and `Set` collections] instead of plain objects if the key values are unknown or not monotonic (i.e., frequently added then removed). |
| | 28 | * Use `hsla()' over hex or RGB colors in CSS. |
| | 29 | * Use `for..of` syntax when performing actions on each element. Use `forEach` when chaining methods in a functional style. Use a classical for loop when doing index math. |
| 62 | 63 | * To reject a promise, throw an `Error` instance or call the `reject` callback with an `Error` instance. |
| 63 | 64 | * A `.catch()` block is considered resolved if it does not re-throw an `Error` instance. Re-throw if you want to log an error message and allow other parts of a chain (i.e, an API client) to handle an error condition. |
| 64 | 65 | * Don't directly pass a promise's `resolve` function to `Object.addEventListener`, as it will leak the promise if the event never fires. Instead, use a single-fire `WebInspector.EventListener` object defined outside of the promise chain and connect it inside a `.then()` body. Inside the `.catch` block, disconnect the `EventListener` if necessary. |
| 65 | 66 | * For APIs that return promises, document what the fulfilled value will be, if any. Example: `createSession() // --> (sessionId)` |
| | 67 | |
| | 68 | == Arrow Functions |
| | 69 | |
| | 70 | Arrow functions simplify a common use of anonymous functions by providing a shorter syntax, lexical binding of `this` and `arguments`, and implicit return. While this new syntax enables new levels of terse code, we must take care to keep our code readable. |
| | 71 | |
| | 72 | === Implicit return |
| | 73 | |
| | 74 | Arrow functions with one expression have an implicit return. All of these are equivalent (modulo `this` binding, arguments, constructor usage, etc.): |
| | 75 | |
| | 76 | {{{ |
| | 77 | 1 let foo = val => val; |
| | 78 | 2 let foo = (val) => val |
| | 79 | 3 let foo = (val) => val; |
| | 80 | 4 let foo = (val) => { return value++; } |
| | 81 | 5 let foo = function doStuff(val) { return value++; } |
| | 82 | }}} |
| | 83 | |
| | 84 | Never use option (1), because it is a special case that only applies when the function has one argument, reducing predictability. |
| | 85 | |
| | 86 | In cases where the return value is used and the expression is a constant ("foo"), a variable (foo), or a member (this.foo), use option (2) (with braces if the arrow function is inlined). |
| | 87 | |
| | 88 | In cases where the expression computes a value (a + 42) or performs a side effect (++a), prefer option (4). |
| | 89 | In some sense, curly braces are a signpost to the effect of "careful, we do actual work here". |
| | 90 | |
| | 91 | GOOD: |
| | 92 | |
| | 93 | {{{ |
| | 94 | setTimeout(() => { testRunner.notifyDone(); }, 0) |
| | 95 | }}} |
| | 96 | |
| | 97 | BAD: |
| | 98 | |
| | 99 | {{{ |
| | 100 | setTimeout(() => { testRunner.notifyDone() }, 0); // return value not used |
| | 101 | }}} |
| | 102 | |
| | 103 | === When not to arrow |
| | 104 | |
| | 105 | When assigning a function to a subclass prototype (in the old way of setting up classes), always use the normal function syntax, to avoid breaking subclasses who use a different 'this' binding. Note that arrow functions are NOT acceptable for assigning functions to singleton objects like WebInspector, since the captured lexical `this` is typically the global object. |
| | 106 | |
| | 107 | GOOD: |
| | 108 | |
| | 109 | {{{ |
| | 110 | Base.prototype.compute = function(a, b, c) { ... } |
| | 111 | Foo.prototype.compute = function(a, b, c) { Base.prototype.compute.call(this, a, b, c); } |
| | 112 | |
| | 113 | WebInspector.UIString = function(format, args) { ... } |
| | 114 | }}} |
| | 115 | |
| | 116 | BAD: |
| | 117 | |
| | 118 | {{{ |
| | 119 | Base.prototype.compute = (a, b, c) => { ... } |
| | 120 | Foo.prototype.compute = (a, b, c) => { Base.prototype.compute.call(this, a, b, c); } |
| | 121 | |
| | 122 | WebInspector.UIString = (format, args) => { ... } // this will be window. |
| | 123 | }}} |
| | 124 | |
| | 125 | Also use the normal function syntax when naming an anonymous function improves readability of the code. In this case, use Function.prototype.bind or assign the arrow function into a local variable first. |
| | 126 | |
| | 127 | GOOD: |
| | 128 | |
| | 129 | {{{ |
| | 130 | Promise.resolve() |
| | 131 | .then(function resolved(value) { ... }, |
| | 132 | function rejected(value) { ... }); |
| | 133 | }}} |
| | 134 | |
| | 135 | BAD: |
| | 136 | |
| | 137 | {{{ |
| | 138 | Promise.resolve() |
| | 139 | .then((value) => { ... }, |
| | 140 | (value) => { ... }) |
| | 141 | }}} |
| 117 | | |
| 118 | | == Old class skeleton |
| 119 | | |
| 120 | | Some existing Inspector object classes have not been converted to ES6 classes. The should conform to the following format: |
| 121 | | |
| 122 | | {{{ |
| 123 | | WebInspector.NewObjectType = function() |
| 124 | | { |
| 125 | | WebInspector.Object.call(this); |
| 126 | | |
| 127 | | this._propertyName = ...; |
| 128 | | } |
| 129 | | |
| 130 | | WebInspector.NewObjectType.Event = { |
| 131 | | PropertyWasChanged: "new-object-type-property-was-changed" |
| 132 | | }; |
| 133 | | |
| 134 | | WebInspector.NewObjectType.prototype = { |
| 135 | | constructor: WebInspector.NewObjectType, |
| 136 | | __proto__: WebInspector.Object.prototype, |
| 137 | | |
| 138 | | // Public |
| 139 | | |
| 140 | | get propertyName() |
| 141 | | { |
| 142 | | return this._propertyName; |
| 143 | | }, |
| 144 | | |
| 145 | | set propertyName(value) |
| 146 | | { |
| 147 | | this._propertyName = value; |
| 148 | | this.dispatchEventToListeners(WebInspector.NewObjectType.Event.PropertyWasChanged); |
| 149 | | }, |
| 150 | | |
| 151 | | publicMethod: function() |
| 152 | | { |
| 153 | | /* public methods called outside the class */ |
| 154 | | } |
| 155 | | |
| 156 | | // Protected |
| 157 | | |
| 158 | | handleEvent: function(event) |
| 159 | | { |
| 160 | | /* delegate methods, event handlers, and overrides. */ |
| 161 | | }, |
| 162 | | |
| 163 | | // Private |
| 164 | | |
| 165 | | _privateMethod: function() |
| 166 | | { |
| 167 | | /* private methods are underscore prefixed */ |
| 168 | | } |
| 169 | | }; |
| 170 | | }}} |