Skip to content

DISCUSSION: Enforce JSHint W084?#4345

Closed
Hamms wants to merge 1 commit into
stagingfrom
jshint-W084
Closed

DISCUSSION: Enforce JSHint W084?#4345
Hamms wants to merge 1 commit into
stagingfrom
jshint-W084

Conversation

@Hamms

@Hamms Hamms commented Oct 5, 2015

Copy link
Copy Markdown
Contributor

According to our style guide, we default to following Google's style guide which makes the following recommendation:

Iterating over Node Lists

Node lists are often implemented as node iterators with a filter. This means that getting a property like length is O(n), and iterating over the list by re-checking the length will be O(n^2).

var paragraphs = document.getElementsByTagName('p');
for (var i = 0; i < paragraphs.length; i++) {
  doSomething(paragraphs[i]);
}

It is better to do this instead:

var paragraphs = document.getElementsByTagName('p');
for (var i = 0, paragraph; paragraph = paragraphs[i]; i++) {
  doSomething(paragraph);
}

This works well for all collections and arrays as long as the array does not contain things that are treated as boolean false.

This pattern is used quite frequently in blockly-core. Unfortunately, this pattern violates JSHint W084, AKA boss, which protects against assignments going in unexpected places. Most commonly, if (x = 'foo') rather than if (x == 'foo').

Note that JSHint supports the following:

You can silence this error on a per-use basis by surrounding the assignment with parenthesis, such as:

for (var i = 0, paragraph; (paragraph = paragraphs[i]); i++) {}

For consistency, we should do one of the following:

  • modify our JSHint config to ignore W084 and expose ourselves to the possibility of that error.
  • update our style guide to reflect that we do not allow assignment in the conditional and begin the process of updating blockly-core to reflect this. The commit below gives an example of what that would look like for a single file.
  • update our style guide to reflect that we follow Google's style, but with the added requirement that you wrap your assignments in parenthesis, and begin the process of updating blockly-core to appropriately wrap all instances of this pattern in parenthesis.

Thoughts?

@Hamms

Hamms commented Oct 7, 2015

Copy link
Copy Markdown
Contributor Author

vim script used to edit file, for posterity:

#!/bin/bash
vim -c "%s/^\(\s*\)\(.*\); \(\w*\) = \(.*\)\[\(.\)\];\(.*\)$/\1\2; \5 < \4.length;\6\r\1  \3 = \4[\5];/gc" $@

@laurelfan

Copy link
Copy Markdown
Contributor

Vim script! Maybe you should do a brown bag on that.

On Oct 6, 2015, at 19:05, Elijah Hamovitz notifications@github.com wrote:

vim script used to edit file, for posterity:

#!/bin/bash
vim -c "%s/^(\s)(.); (\w) = (.)[(.)];(.*)$/\1\2; \5 < \4.length;\6\r\1 \3 = \4[\5];/gc" $@


Reply to this email directly or view it on GitHub.

@Hamms

Hamms commented Oct 7, 2015

Copy link
Copy Markdown
Contributor Author

Ooooh. On vim or regexes? Cause I do love both

@Bjvanminnen

Copy link
Copy Markdown
Contributor

I personally find approach number 1 much more readable. I would be interested in seeing some jsperf analysis of what the performance delta between the two approaches is if anyone knows how to use jsperf well.

Another approach for these types of iterations is to use forEach

var paragraphs = document.getElementsByTagName('p');
paragraphs.forEach(function (paragraph) {
  doSomething(paragraph);
}

Not sure what the cost of calling a function for each iteration is.

If we were using ES6, we could instead do

var paragraphs = document.getElementsByTagName('p');
for (let paragraph of paragraphs) {
  doSomething(paragraph);
}

@islemaster

Copy link
Copy Markdown
Contributor

👍 upvote on the parentheses-wrap solution. I think W084 is a useful check because it covers a specific 'silent but deadly' type of bug, so I don't want to disable it entirely.

@Hamms

Hamms commented Oct 7, 2015

Copy link
Copy Markdown
Contributor Author

unfortunately, blockly-core makes frequent use of HTMLCollections, which do not support forEach

@Hamms

Hamms commented Oct 7, 2015

Copy link
Copy Markdown
Contributor Author

well, according to jsperf Google doesn't know what they're talking about

@Bjvanminnen

Copy link
Copy Markdown
Contributor

It's possible that their statements once held true, but that compiler improvements have since optimized for the other (arguably more readable) case

@Hamms

Hamms commented Oct 7, 2015

Copy link
Copy Markdown
Contributor Author

Aye, so I'd assume. In my mind, the performance difference gives #2 a bit of an edge over #3, although #3 is certainly the easier solution.

@Hamms

Hamms commented Oct 7, 2015

Copy link
Copy Markdown
Contributor Author

After a few more jsperf tests, it looks like the performance issue is real in every browser EXCEPT Chrome. Crafty, Google.

Unless there are objections, I'm gonna go with the third option, and will update our styleguide appropriately.

@Hamms Hamms closed this Apr 20, 2016
@Hamms Hamms deleted the jshint-W084 branch May 11, 2016 23:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants