Absolutely. We've found automated style checking also improves quality and efficiency. Even the "pedantic jerk" can miss small style issues that are easily caught by tooling.
For anyone wondering what tools. The most common for JS are JSHint and JSCS. Then use Grunt or Gulp combined with a watch to check a file each time a change is saved. Lastly, use a precommit hook (or similar) to check again before code is committed into the repo.
I learned something: I didn't know that the difference between:
function foo() {
}
and
var foo = function() {
};
Was that with the first form foo() will always be declared and available for use inside a scope, while the second form depends at which point it is declared.
But I had read somewhere (can't remember where... jshint?) a long while ago that using the latter form inside scopes was better, so I've adopted that.
I don't think I will go with the guide for this one, since not having the function defined automatically is often useful, to avoid overhead of instantiating the function for when it's not going to be used due to code flow.
This is referred to as "hoisting". As an aside, technically the latter's `var` declaration also gets destructured and hoisted as such...
var foo;
...
foo = function() {
}
Also another difference in the latter is that its an anonymous function, which is commonly seen in assignment expressions — but you could also name it for more informative logging.
Nice trick, thanks! The "anonymous" function is especially annoying when profiling code, so that should address that annoyance. I often struggle with picking names, but another post here shows that "foo" can just be reused as the function name.
> I often struggle with picking names, but another post here shows that "foo" can just be reused as the function name.
I'd be very careful about giving them the same name if you're working with IE at all. IE8 and below's JScript does some really strange stuff with function expressions, leaking and hoisting them all over the place. [1]
Instead, I'd just append a character or something to differentiate the two. I've been using the format advocated for in Javascript Patterns[2][3]:
A lot of people prefer the latter form inside scope, because it disambiguates the ambiguity that hoisting introduces: define your function at the bottom of the scope, and it'll still be available at the top. By assigning it to var, you delineate "this function can be called by any line in this scope after this one, but not by any line before it." You also remove a named reference to it from the stack trace.
I much prefer dealing with the "weird" "confusion" hoisting behavior than with not having a named function in my stack trace.
Ah, right. Should have left the original comment alone.
Here's why you shouldn't rely on function hoisting: it gets weird. Weird enough that MDN has a section on it's "oddities" [0]. And since it doesn't add any expressive power, there's no compelling reason not to just treat all your code as data.
Or limiting when/where you define named functions it's pretty damn silly to declare a named function within an if block within a function call, especially if it has the same name as a function you've defined outside of it.
I tend to limit them to "private" module functions. e.g.,
"use strict";
/*global module:true*/
function add(a, b) {
return a+b;
}
module.exports = {
sum : function(list) {
return list.reduce(add, 0);
}
};
I don't declare named functions in a scope smaller than the module itself, so I don't really run into the 'weirdness' of hoisting.
Then again, I've moved to commonjs style modules for everything - server side with node, client side with browserify (webpack does weird things with require()).
I'd be in complete agreement if it offered any substantive benefits; however, I've yet to see an example of function-hoisting that can do something regular var-hoisting can't.
Yes, actually it does. A named function expression and a function declaration are distinct concepts. The latter is function-hoisted (the whole body goes to the top), whereas the former is only var-hoisted (the body remains in place).
What browser are you using? As far as I can tell, all modern browsers know how to get the name of a function defined like `var foo = function(){}` for stack traces.
With overhead, the approach I try to stick to is unless the code become more difficult to grasp, avoid overheads, however small they may be, whenever they can be avoided. Everything adds up in the end.
> Always put 'use strict'; at the top of your modules.
'use strict'; should be in the top of the scope you control. A global 'use strict'; would place the global scope into strict mode, so all your imported modules would be under strict mode too, and then third party code would break and you don't know why. IIRC jshint will pick this up.
I'm not convinced that this guide is very good. On many of the issues the actual decision is punted in favor of "just make sure it's consistent". Well obviously, that's why there's a guide. The purpose is to lay down the law so everyone knows HOW to be consistent.
Moreover, a few of the suggestions introduce serious performance issues, notably around iteration and the treatment of the `arguments` object. If you haven't yet, please do check out Petka Antonov's Optimization Killers [0].
It really depends on whether performance is an issue, and the cost of the optimisation.
A common example: lodash searches function toString() with regexps as an optimisation technique, underscore doesn't. Both are correct, maintaining lodash requires knowledge of how and why the hack works, but OTOH lodash is faster. Maintaining underscore is cognitively simpler but the resulting code is slower.
I'm all about making sure that code is optimized for humans first and computers second.
Here is the specific remark I was referring to: Or even better, just use .forEach which doesn't have the same caveats as declaring functions in for loops.
Blindly applying forEach is simply not the right answer here.
I'd suggest the opposite: forEach() is smaller that iterating over indexes and creates a scope by default which (although having overhead) will prevent a lot of common last-case-wins scenarios that frequently trap both new and experienced developers.
Should we use a .forEach() for a 1 million item array? No. Performance would be a problem. For the typical use case of items like the demo [1, 2, 3]? Yes, this would be be simpler.
The best quality/style guide I've ever been given was:
"our code will be read many more times than it was written, don't do stupid shit". Having worked in that team for a while I really can't see any use for this kind of granular detail, other than if you goal really is over-zealous control.
> Keep regular expressions in variables, don't use them inline. This will vastly improve readability.
Although it might introduce inadvertent bugs. I prefer not to follow that advice to avoid running into the 'lastIndex' problem described here [1]. There are other ways to avoid it like not using the 'g' flag or resetting lastIndex. However not storing regex in a variable is also useful to avoid that headache. You might argue about performance but for a good majority of the cases, it doesn't matter practically.
It seems to be fashionable recently to omit semicolons from Javascript. For example GitHub (internal) and zepto.js have jumped on the no-semicolon bandwagon, requiring their omission in any code.
That's why I don't like guides that suggest people to mindlessly add semicolons everywhere. If you don't really know how ASI works you are always living in the fear of missing a semicolon somewhere. Actually learning how ASI works liberates you from that fear and you can still opt to use or not use semicolons.
I think I'm actually in total disagreement with this. I think using semicolons as statement terminators is quite easy and doesn't require any knowledge of the ASI in terms of _adding_ semicolons. The one (potential) issue with not being aware of the ASI when using semicolons as statement terminators is for something like:
return
{
a: 0
};
since you can't disable ASI. Even in the above case, however, "standard" JS style would prevent the issue.
Relying on "standard JS style" is as reliable as relying on ASI without knowing how it works.
If what you are saying is with "standard JS style" you will never add a newline after return, then I can also assume with "standard JS style" you will not:
- start a line with ++ or --
- start a line with a regex literal
- split a for statement into separate lines
So, the only issue you need to be aware of when writing semicolon-less javascript is when you start a new line with ( or [. Easy enough to remember, no?
I've personally been writing semicolon-less JS for almost two years now, and this one simple rule has been more than enough.
Don't confuse quality with style. If you want provide a quality guide, include only rules that actually improve the quality of the code, don't include style preferences. Style is subjective by nature, but quality not so much. Some rules being enforced in this guide are heavily opinionated and yet have no direct correlation with code quality. What does the indentation being 2 spaces or 4 spaces or tabs have to do with code quality? And a semicolon-less codebase can be as clean, readable and performant as one with semicolons, your arguments against ASI is simply FUD. As many have pointed out, for these stylistic disagreements the only rule should be "just be consistent".
"Usually you'll be a happier JavaScript developer if you hack together a parameter-replacing method like util.format in Node."
+
"You could implement something similar using the piece of code below."
I don't think you can ask more than this, everything is clearly laid out...
I think you'll find that most frontend developers despise 4 spaces...at least that I've come upon anyhow. I only ever met one developer that liked 4, and that person is a tab guy to boot.
I'm a front-end guy and I love my 4 spaces. Helps a lot with complicated HTML to have the extra spaces to easily see what is what. It's also very useful in SASS and Less, where you have nesting.
As someone who prefers tabs, but doesn't care enough so will happily use spaces, I've never understood the hatred around tabs.
Not only does it remove the 2 vs 4 spaces debate (just set your browser preferences to display it as whatever!), it's more 'semantically correct' - it's literally saying "one level of indentation please".
Anyway, not that I particularly care - I just always found it amusing that this is where developers have chosen against things being semantically correct and user-configurable.
I used to prefer tabs (for the exact reason, tabs indicate an indent, spaces indicate a space) except for one edge case that has me using spaces now. If you're anal about making sure chained method calls line up on their own lines, spaces guarantee that across the board, but tabs would mess up the indent.
var foo = SomeTerriblyLongHorrificClass->withUnreasonablyLargeChildren()
->dueToTheOddNumberOfCharachters()
->sometimesItsNiceToUseSpaces()
->here()
Let the computer yell at people so you don't have to.
Nobody wants to be the pedantic jerk who has to leave comments on a PR about whitespace or single vs double quotes.
When you use an automated style checker, you presumably catch those errors before a PR gets submitted and nobody ever has to be the bad guy/girl.