You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/rules/array-foreach.md
+35-22
Original file line number
Diff line number
Diff line change
@@ -1,27 +1,17 @@
1
-
# Array.forEach
1
+
# Array Foreach
2
2
3
3
Prefer `for...of` statement instead of `Array.forEach`.
4
4
5
-
```js
6
-
// bad
7
-
els.forEach(el=> {
8
-
el
9
-
})
5
+
## Rule Details
10
6
11
-
// good
12
-
for (constelof els) {
13
-
el
14
-
}
15
-
```
16
-
17
-
## Why disallow `forEach`
7
+
### Why disallow `forEach`
18
8
19
9
Here's a summary of why `forEach` is disallowed, and why we prefer `for...of` for almost any use-case of `forEach`:
20
10
21
-
- Allowing `forEach` encourages **layering of "bad practices"**, such as using `Array.from()` (which is less performant than using `for...of`).
22
-
- When more requirements are added on, `forEach` typically gets **chained** with other methods like `filter` or `map`, causing multiple iterations over the same Array. Encouraging `for` loops discourages chaining and encourages single-iteration logic (e.g. using a `continue` instead of `filter`).
23
-
-`for` loops are considered "more readable" and have **clearer intent**.
24
-
-`for...of` loops offer the **most flexibility** for iteration (especially vs `Array.from`).
11
+
- Allowing `forEach` encourages **layering of "bad practices"**, such as using `Array.from()` (which is less performant than using `for...of`).
12
+
- When more requirements are added on, `forEach` typically gets **chained** with other methods like `filter` or `map`, causing multiple iterations over the same Array. Encouraging `for` loops discourages chaining and encourages single-iteration logic (e.g. using a `continue` instead of `filter`).
13
+
-`for` loops are considered "more readable" and have **clearer intent**.
14
+
-`for...of` loops offer the **most flexibility** for iteration (especially vs `Array.from`).
25
15
26
16
For more detail, here is a breakdown of each of those points:
27
17
@@ -31,7 +21,7 @@ Typically developers will reach for a `forEach` when they want to iterate over a
31
21
32
22
`forEach` does not do anything special with the Array - it does not create a new array or does not aid in encapsulation (except for introducing a new lexical scope within the callback, which isn't a benefit considering we use `let`/`const`). We don't dissallow `map`/`filter`/`reduce` because they have a tangible effect - they create a new array - which would take _more_ code and be _less_ readable to do with a `for...of` loop, the exception being as more requirements are added, and we start chaining array methods together...
33
23
34
-
### Chaining
24
+
### Chaining
35
25
36
26
Often when using a method like `forEach` - when coming back to add new code, let's say to filter certain elements from the Array before operating on them, a developer is implicitly encouraged to use Array's method chaining to achieve this result. For example if we wanted to filter out bad apples from an Array of Apples, if the code already uses `forEach`, then its a simple addition to add `filter()`:
37
27
@@ -54,12 +44,12 @@ Chaning isn't always necessarily bad. Chaining can advertise a series of transfo
54
44
55
45
### Hiding Intent
56
46
57
-
The `forEach` method passes more than just the current item it is iterating over. The signature of the `forEach` callback method is `(cur: T, i: Number, all: []T) => void` and it can _additionally_ override the `receiver` (`this` value), meaning that often the _intent_ of what the callback does is hidden. To put this another way, there is _no way_ to know what the following code operates on without reading the implementation: `forEach(polishApple)`.
47
+
The `forEach` method passes more than just the current item it is iterating over. The signature of the `forEach` callback method is `(cur: T, i: Number, all: []T) => void` and it can _additionally_ override the `receiver` (`this` value), meaning that often the _intent_ of what the callback does is hidden. To put this another way, there is _no way_ to know what the following code operates on without reading the implementation: `forEach(polishApple)`.
58
48
59
49
The `for` loop avoids this issue. Calls are explicit within the `for` loop, as they are not passed around. For example:
60
50
61
51
```js
62
-
for(constappleof apples) {
52
+
for(constappleof apples) {
63
53
polishApple(apple)
64
54
}
65
55
```
@@ -98,7 +88,30 @@ Compare this to the `for` loop, which has a much simpler path to refactoring:
Accessing `event.currentTarget` inside an `async function()` will likely be `null` as `currentTarget` is mutated as the event is propagated.
4
4
5
+
1. A `click` event is dispatched
6
+
2. The handler is invoked once with the expected `currentTarget`
7
+
3. An `await` defers the execution
8
+
4. The event dispatch continues, `event.currentTarget` is modified to point to the current target of another event handler and nulled out at the end of the dispatch
9
+
5. The async function resumes
10
+
6.`event.currentTarget` is now `null`
11
+
12
+
If you're using `async`, you'll need to synchronously create a reference to `currentTarget` before any async activity.
2. The handler is invoked once with the expected `currentTarget`
20
-
3. An `await` defers the execution
21
-
4. The event dispatch continues, `event.currentTarget` is modified to point to the current target of another event handler and nulled out at the end of the dispatch
22
-
5. The async function resumes
23
-
6.`event.currentTarget` is now `null`
24
-
25
-
## Solutions
26
-
27
-
If you're using `async`, you'll need to synchronously create a reference to `currentTarget` before any async activity.
2. This handler is scheduled but not ran immediately because its marked async.
17
9
3. The event dispatch completes and nothing has called `preventDefault()`_yet_ and the default click behavior occurs.
18
10
4. The async function is scheduled and runs.
19
11
5. Calling `preventDefault()` is now a no-op as the synchronous event dispatch has already completed.
20
12
21
-
## Solutions
22
-
23
13
If you're using `async`, you likely need to wait on a promise in the event handler. In this case you can split the event handler in two parts, one synchronous and asynchronous.
Copy file name to clipboardExpand all lines: docs/rules/authenticity-token.md
+15-5
Original file line number
Diff line number
Diff line change
@@ -1,4 +1,6 @@
1
-
# `<input name="authenticity_token">`
1
+
# Authenticity Token
2
+
3
+
## Rule Details
2
4
3
5
The Rails `form_tag` helper creates a `<form>` element with a `<input name="authenticity_token">` child element. The authenticity-token input tag contains a [Cross-Site Request Forgery (CSRF)](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29) token that is verified by the Rails app when the form is submitted.
4
6
@@ -24,13 +26,13 @@ The preferred way to make an HTTP request with JavaScript is to use the [`FormDa
24
26
```
25
27
26
28
```js
27
-
on('click', '.js-my-button', function(e) {
29
+
on('click', '.js-my-button', function(e) {
28
30
constform=this.closest('form')
29
31
30
32
fetch(form.action, {
31
33
method:form.method,
32
34
body:newFormData(form)
33
-
}).then(function() {
35
+
}).then(function() {
34
36
alert('Success!')
35
37
})
36
38
@@ -45,14 +47,22 @@ An alternate, but less preferred approach is to include the a signed CSRF url in
Copy file name to clipboardExpand all lines: docs/rules/js-class-name.md
+25-5
Original file line number
Diff line number
Diff line change
@@ -1,8 +1,8 @@
1
-
# JS prefixed class names
1
+
# Js Class Name
2
2
3
3
JavaScript should only query and handle events for `js-` prefixed class names.
4
4
5
-
## Statically declared
5
+
## Rule Details
6
6
7
7
The key benefit is that these symbols can be easily searched for.
8
8
@@ -17,15 +17,35 @@ In order to trust this system, all `js-` class names MUST be statically written
17
17
Typically dynamically constructed `js-` classes are often mixing static symbols and user data together. Like `"js-org-#{org.login}"`. In this case, separating into a `data-` attribute would be a better solution.
Allows you to select elements by `js-org-update` and still filter by the `data-org-name` attribute if you need to. Both `js-org-update` and `data-org-name` are clearly static symbols that are easy to search for.
24
24
25
-
## Formatting
25
+
###Formatting
26
26
27
27
`js-` classes must start with `js-` (obviously) and only contain lowercase letters and numbers separated by `-`s. The ESLint [`github/js-class-name`](https://github.com/github/eslint-plugin-github/blob/master/lib/rules/js-class-name.js) rule enforces this style.
28
28
29
-
## See Also
29
+
###See Also
30
30
31
31
[@defunkt's original proposal from 2010](https://web.archive.org/web/20180902223055/http://ozmm.org/posts/slightly_obtrusive_javascript.html).
0 commit comments