Non-ambiguous titles also matter, in this case it should be "Semicolons matter in JavaScript". Too many links have this problem and it makes it difficult to find an article when searching for something on HN.
I know it's not kosher to say "me too" in the comments, but "me too"; I like using semicolons when the previous independent clause doesn't seem substantial enough to be its own complete sentence.
Honestly when you already have to keep track of JavaScript's other gotchas, having to remember to look for likes that start with ( or [ and precede then with a semicolon is not that much to ask. It seems silly anyway, but not particularly damaging.
The problem here is that the assignment to Logger.prototype.log superficially looks like a function definition, not like an assignment statement, especially when you don't look too hard at the beginning.
I have a short anecdote where not using semicolons caused problems. Or well, not even in our code.
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.
Yeah. I haven't run into these sorts of problems since using a bundler that doesn't just do plain file concatenation (Webpack, Browserify, etc). I think that if you write clear, unambiguous code, and use ES6 modules via Webpack, you can (fairly) safely drop semicolons.
You should install eslint or a similar tool; they have configurable warnings about things like that and will tell you where you should be putting semicolons.
Seems like everyone should just be using an automated tool to catch missing/extra semicolons. No reason not to at this point, and eslint even autofixes them for you.
Outside of work, I spent a month or two writing little demos for my kids in javascript using notepad. My old computer had died and I was borrowing one. This was in ~2014 maybe?
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.
Correct me if I'm wrong, but the only case you have to worry about is having "return" on the same line as the thing you want to return. And you have that problem whether or not you use semicolons in the rest of your code.
The blog post mentions, that starting a line with [ or ( can be dangerous too.
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 :)
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.
The idea is that leaving out a semicolon saves an almost imperceptible amount of time but requires you to be deeply familiar with the rules of every JavaScript engine, any minifiers/transpilers/etc. which will ever see that code, etc. and also commits you to rigourously applying that logic to every future change.
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.
If you're writing idiomatic modern javascript you're using modules -- we no longer have the issue of two JS files being concatenated together in a shared lexical scope. The only rules you need to be familiar with are the 2 I mentioned. In my work, I've never thought about it as "imperceptible" time savings: I worked on a codebase without semi-colons, and then didn't want to go back. It was easier code to work with and write, and the feared downsides never materialized.
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.
If you're using an editor to automatically pair your parens/brackets/braces/quotes, you now have to find and navigate to the end of the expression, which could be lines away if you're creating objects and arrays, or calling functions with complex arguments.
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.
I never have to "look at the next line and reason about it" -- you simply do not find yourself in a position very often of starting a line with an open brace. I'm not going to list all of the little reasons why I found it more enjoyable and easier to omit the semicolons. If you're interested, try it on a project yourself. Suffice to say, I found several cases where my life was just easier. Here's just one, from the very top of a file. It's easier to add another import to this list:
let states = require('../data/states.json')
, cloneDeep = require('lodash/cloneDeep')
Again, I have tried this and fail to see any more benefit than, say, changing the indent size in my editor. Personally, I prefer
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.
You have strong opinions about this. That's cool, and if you believe one way is more correct that's also cool. My advice to everybody is the same advice I gave you: try it. Try project without them and see. The only risk is that you might find out you're wrong. If you want to add them later there are tools for that.
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.
Kind of insane that this still hasn't been fixed. You should be able to put something like `strict_semicolons;` at the start of a JS file to tell the interpreter to require semicolons for that file.
So do Lisp, Haskell, OCaml, Python, and Perl. They're all different languages and should be expected to have grammatical differences. This is not a new trend.
The essential difference between Javascript and Go is that in Go, the semicolons are inserted by the lexer[0], while in JS, they're inserted by the parser. I don't know how Rust does it.
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.
Can someone explain what's happening here? I'm a JavaScript dev, perfectly familiar with JS and with semi-colon insertion, but I'm not following the code after "This is how V8 sees it:"
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.'
He probably left the function empty to keep it simple. And with "perfectly valid code" he's probably referring to not having any syntax error's, which is true.
I believe the issue is that the code gets parsed as a function expression that is being indexed by a series of strings in comma expressions. This happens instead of automatic semicolon insertion jumping in and then giving you the "expected" code.
As a brief aside, TypeScript could help catch this sort of thing with its `--noImplicitAny` flag turned on.
I like working on code bases without semi colons better than those with, because the choice to drop is indicative of the team's attitudes, and I often find many other things I like about those softwares.
The rules to drop them are simpler than the rules to keep them.
> 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.
Flame-on:
I wish I could blacklist other people's code that don't use semicolons. Perhaps that flagging should be put into a linter. That linter will then update a global list of semicolon-optional code.
Flame-off.
87 comments
[ 4.0 ms ] story [ 84.0 ms ] threadFor the record, I didn't post my article here, but if I had I would have specified the language.
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
}());
function Logger() { }
// Log something to the console at a specified level
Logger.prototype.log = function(level) {
}; // here// Sugar functions for Logger.log
['info', 'warn', 'error'].forEach(function(level) {
});I understand this is the case, I just want to know why. The value is set, it seems like it should end the statement.
Tabs or spaces?
Brains are wired differently plus we "higher" monkeys take our habits seriously serious!
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 :)
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.
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.
[0] https://golang.org/doc/effective_go.html#semicolons
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
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-...