Semicolons matter
blog.rrowland.com
blog.rrowland.com
> When your code’s intention is ambiguous, your JavaScript engine will attempt to fill in the gaps.
This is kind of misleading. The JS engine isn't making some guess. There are clearly defined semantics on how ASI (automatic semi-colon insertion) operates. Let's put aside whether ASI is good or bad-it's just part of JavaScript. Ending all your lines with semi-colons won't save you, only understanding ASI will do that.
Take this example:
function foo() {
return
'A really long string that I've put on another line';
}
console.log(foo());
You'll see that `foo` returned undefined here. Why? Because ASI terminated `return\n` as a statement.Isaac Schlueter wrote a post on this years ago that pretty much says everything I'd want to say on this topic: http://blog.izs.me/post/2353458699/an-open-letter-to-javascr...
Half of this article is a strawman argument under the heading: "You can’t minify JavaScript code without semicolons"
I've never heard that argument in my life for using semicolons.
> Easy solution: when a line starts with parenthesis, prepend a semicolon to it.
Sweet! Something extra to remember because I chose not to use semicolons.
> My advice on JSLint: don’t use it. Why would you use it? If you believed that it helps you have less bugs in your code, here’s a newsflash; only people can detect and solve software bugs, not tools. So instead of tools, get more people to look at your code.
Are you kidding me? This has to be trolling. Our goal as programmers is to automate tasks and save people time. What kind of garbage is this?
>Half of this article is a strawman argument under the heading: "You can’t minify JavaScript code without semicolons" I've never heard that argument in my life for using semicolons.
This does unfortunately still happen. Even in this HN discussion, it's been brought up. Nowadays, every minifier follows proper ASI semantics. Concatenation is something you need to be careful of, but that's more of a general thing that has nothing to do with whether or not semicolons are used. Joining files with ";\n" and wrapping contents in IIFEs work well.
> Sweet! Something extra to remember because I chose not to use semicolons.
A linter can catch this for you, so you don't actually have to remember anything. Regardless, it's a simple rule: Prepend a semi-colon to lines that start with '[' or '('. This is much simpler and less noisy than "Put a semi-colon in most places that terminate a statement".
More importantly though, I'd say that ASI rules are something everyone should be aware of, regardless of whether or not one chooses to use semicolons.
> Are you kidding me? This has to be trolling. Our goal as programmers is to automate tasks and save people time. What kind of garbage is this?
Agreed. JSLint in particular is quite rigid, so I'd avoid using it, but ESLint is a fine alternative that can be configured to check for both semicolon and semicolon-free styles.
return
"something";
is parsed as return;
"something";
??? That's just braindead.What we really need is for an analog of "use strict" (e.g. "use strict semicolons" that either (a) eliminates semicolon insertion from Javascript (and just starts throwing errors) or (imho better) (b) eliminates the semicolon altogether (aside from inside for()). Since a huge proportion of production js is being linted using tools that force semicolon insertion, the first option would be pretty painless.
Option b — making newline the semantic replacement for ';' would actually be better, since it prevents atrocities like:
function wtf(x){ console.log('wtf', x); } /* newline here; strictly correct js */ ("hello world")
It will save you if you use JSLint/JSHint/ESLint/etc.
In your example you will get an error about a semicolon missing after the return statement.
If your convention is to always use semicolons your editor can let you know you have made a mistake. If you don't use semicolons then you have to turn off these warnings from your Linter and you won't catch the error until you see weird results at runtime.
And that's the purposing of always using semicolons, so you can have automated tools help you.
For the record, I didn't post my article here, but if I had I would have specified the language.
function Logger() { }
// Log something to the console at a specified level
Logger.prototype.log = function(level) {
console[level || 'log'].apply(console,[].slice.apply(arguments, 1));
}; // here// Sugar functions for Logger.log
['info', 'warn', 'error'].forEach(function(level) {
Logger.prototype[level] = function () {
return this.log.apply(this, [level].concat(Array.from(arguments)));
}; // here
});I understand this is the case, I just want to know why. The value is set, it seems like it should end the statement.
"semi": [2, "never"], // Disallow semicolons
"no-unexpected-multiline": 2, // Prevent edge cases caused by excluding semicolons.
And I haven't thought about it since. I'd expect an article like this 5 years ago, but it feels like bikeshedding at this point. If you choose to not use semicolons then add lint rules to protect against the edge cases and stop wasting brainpower on it.Gist: Adding semicolons won't help, because you still have to know how JavaScript inserts them automatically to add them in the right places.
But till hat example I didn't even know why this would make sense in the first place.
I only use excessive parenthesis for math and store arrays, like the example, in constants that describe their purpose, so I guess I dodged a bullet there :)
We're still going over this? Javascript, The Good Parts came out close to 10 years ago and went over this.
We were using (IIRC) a version of underscore.js that did not use or did not end the final line thing (probably one of them self-executing functions) with a semicolon. Because of reasons, our application would break in production builds; the lack of semicolons would, in some cases, cause an issue after concatenating that file with another vendor's file. A very obscure and hard to track one, too - it took us weeks if not months to find it.
;(function () {
// Library here
}());
I don't see how or why the two lengthy statements using `apply` are being omitted entirely. I also don't see how that's "perfectly valid code" . . . I tried running it and got an error 'cannot read property forEach of undefined.'
As a brief aside, TypeScript could help catch this sort of thing with its `--noImplicitAny` flag turned on.
The content of the functions is just not relevant to the point he's trying to make
http://blog.izs.me/post/2353458699/an-open-letter-to-javascr...
Either way, no matter your preference, the issue is resolved by having a linter, not by scrutinizing your code for missing semicolons. The OP post feels very dated.
That's where I'd expect this to come up most frequently – someone writes code, tests it, it works and they move on but later someone makes a change and doesn't notice that the original author left a trap for them. It's easy to avoid that in the “ASI is cool” examples but real programs evolve over time and you never want to make maintenance programming harder.
I still use them to conform with existing code bases or linters that require them, of course, but given the preference..
This is the part I'm still having trouble with – hitting ";" at the end of a statement is harder than having to look at the next line and reason about it? I mean, we're talking about a single character on the home row of most keyboards – just how fast are you cranking out code?
EDIT: just to be clear, I don't see this as a huge factor either way – a formatter can easily add or remove to your preference – so I surprised by the way ASI proponents talk about it as a big deal. To me it seems like a minor aesthetic preference on the level of “2 spaces or 4?” which doesn't meaningfully change the way you're writing code and is significantly outshone by something like switching to ES6, etc.
When coding, my cursor is rarely just "at the end of a statement" on its own. The only way it typically gets there is by me intentionally placing it there.
Refactoring is a bigger hassle as well. You may want to use the return of your statement as an argument to some new function. Now the semi has to be removed and added elsewhere.
It's not the end of the world, but it's a hassle.
let states = require('../data/states.json')
, cloneDeep = require('lodash/cloneDeep') let states = require('../data/states.json'),
cloneDeep = require('lodash/cloneDeep');
to let states = require('../data/states.json')
, cloneDeep = require('lodash/cloneDeep')
but that's an unimportant aesthetic preference. The structure of the code is the same and my experience working with it is fundamentally unchanged. In either case we're talking about a fraction of a percentage of the time it takes to understand what the application is or should be doing.Now compare that to something which actually matters: arrow functions, classes, modules and imports, the newer data structures, generators, etc. In that case, the time spent adopting a new style actually changes the structure of the code you're writing and, hopefully, makes it easier to clearly convey your intention to the next person who works on it.
It's odd that you appear to have ready my comments but missed the point where I repeatedly said that I do not have a strong opinion about this and was expressing my surprise that some people do.
This means that Go's semicolon insertion rules are really simple: to judge if a statement will end in a semicolon, you only need to examine that line (actually, the last token of that line).
In Javascript, on the other hand, the start of the next line needs to be considered as well. If the two lines could possibly be interpreted as one statement together, then they are (except for restricted productions). [ and ( are common offenders that cause lines to "pick up" other lines, but unary + and - can also be candidates when they get promoted to binary operators.
A semicolon doesn't seem like much but that's a lot of extra typing over the course of a career.
Yeah, pretty much the only "rules" are to know never to add a line break after keywords such as return (which is the same rule as languages such as Python and which is also something you have to know, regardless of semicolons) and the "Winky Frown Rule": (, [, and ` all have to be winky frowns if you start a line with one: ;(, ;[, ;`
It's pretty liberating writing JS/ES/TS without semicolons, and with ES2015 syntax things, makes the language feel like Python or an OCaML relative (which it sort of is).
I'll stick to caring about he myriad issues that actually cause quality problems for me rather than worry about obscure theoretical bugs.
Tabs or spaces?
Brains are wired differently plus we "higher" monkeys take our habits seriously serious!
While you go have a beer
Where is my module support?
Where is my linter library?
Where is my code ending?
Where have all the semicolons gone?
--- Sing to Paula Cole's "Where have all the Cowboys Gone?"
The rules to drop them are simpler than the rules to keep them.
Hmm. "Semi-colon at the end of each statement" is a pretty easy rule, and I think it'll be hard to top that in simplicity. But I'm open if you've got one.
[1] http://stackoverflow.com/questions/1834642/why-should-i-use-...