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 | | }}} |