JavaScript is one of the most flexible and lenient programming languages out there, compared to the likes of Java or C++ which have much stricter rules. This means that often we encounter unexpected behaviour, even when we are writing the same code that we have written and tested before. As programmers, we do not like anything unexpected (except for of course, Math.random(). We all love Math.random()!) and so we strive to minimise these 'wrong' ways of writing code, that may or may not work at any point in time.
This article is intended for audiences with limited experience of JavaScript, and limited understanding of the language. I will be regularly posting articles both for relatively new JavaScript programmers and more advanced articles for experienced programmers. If you code in JavaScript, you might want to follow me.
1) Avoid Global Scope wherever possible
It is from personal experience that I am telling you this - global scopes are ALWAYS a pain to work with. Generally, you bundle JavaScript files by putting them in an html
file using the <script>
tag. This means that it is as if all these files were written together inside one single file, unless you use modules or some next generation tool like Babel.
There are many examples, many of which are complex to understand the importance of, but I'll try my best for this simple scenario.
Imagine you wanted to store some data for a canvas sketch, and you do it like this:
let canvasWidth = 5;
let canvasHeight = 67;
let canvasMousePos = { x: 9, y: 6 };
This could be fine, but then when you want to add more properties for your canvas, you will pollute the global namespace even more. We use Object
literals for this purpose. It is generally bad practice to store ANY similar data in separate global namespaces, which is also very good for when you need to expand. The following code shows a better way, and shows also for when you might want to include two canvases with different properties in the future.
let mycanvas = { width: 5, height: 67, mouse: { pos: { x: 9, y: 6 } } };
let myothercanvas = { author: 'John', width: 50, height: 107, mouse: { pos: { x: 9, y: 6, z: 89 } } };
If you were paying attention, you might suggest using an Array
to store these two canvases to further remove pollution of the global scope, which is exactly what you should do. At a certain point, you might want to start solving these problems with Object Oriented Programming.
2) Do not omit Semi Colons
A feature that many new and amateur developers love about JavaScript is the fact that in most cases, semicolons ( ; ) are optional and the code runs without them. This feature is known as Automatic Semicolon Insertion. However, using this feature is not recommended and you should include any due semicolons as this can result in unexpected behaviour. Semi colons are also crucial for better readability.
3) JavaScript Array Methods
We store lists in arrays and generally this is so that at some point in our code we will iterate over them, or do some sequential manipulation of this data. Array methods are really useful here.
Imagine I have an array of users
each of whom has a name and some other properties associated with it. If I wanted only the names of these users I could make a new array, loop over the original array and push items into this new array like the first snippet, or we could just use the map
method on our array.
const users = [{ name: 'John', age: 87, post: 'high' }, { name: 'Doe', age: 43, post: 'low' }];
const names = [];
for(let i = 0; i < users.length; i++) {
names.push(users[i].name);
}
// alternatively, in one line
const names = users.map(user => user.name); //["John", "Doe"]
For a list of all array methods and their use cases, click here
4) Reusing any piece of code? Make it a function
How often does it happen that you write some functionality but have to use it again at some other place? I guess very often is the answer for everyone. Whenever you see yourself reusing a piece of code, even if it is just two times, make it into a function. This will mean that if you want to change how that code works in the future (and trust me this will always happen), you will only need to change this in one place instead of 23 places inside 5 JavaScript files.
5) Make your code concise wherever possible
JavaScript code allows flexibility in syntax. So much so that it is possible to make code blocks very concise by omitting redundant parts of the syntax, without breaking recommended patterns. For example the following omits curly braces where they are redundant.
if (this.isHungry()) this.stroll()
else if (inPerception.length <= 2) this.stroll(() => this.inPerception > 2);
else {
this.cohesion(inPerception, cohesionPriority / 100);
const colliding = peerTree.retrieveFromRadius(pos.x, pos.y, r, this.isOfTypeSelf);
this.seperate(colliding, seperationPriority / 100);
}
*This code is from a project that Simulates Evolution in Intelligent Autonomous Agents
This feature must be used with extreme caution and only where statements succeeding expressions are singular. Generally only include curly braces where you have to encapsulate more than one statement, otherwise, omit them for better readability and less redundancy.
Conclusion
You might have noticed that I have given particular importance to the fact that code should be easy to expand upon in the future, and it should be neat to look at and comprehend for anyone (not just you). This is one of the key concepts programmers follow. If you have more tips for new programmers, leave them in the comments below.
If you have read this far, you should be tempted to leave a love react and see how happy that makes both of us ;)
Top comments (17)
I don't agree with point 5, omit semi colon but do ommit braces? That is the same issue. Do use braces, don't rely on whitespace. Or do the opposite, don't do both.
Using braces even for only one statement was in our guidelines on a previous project. A new guy "defied" it, saying it was nonsense. Then it bit him in the a** a couple of times. Now he uses them everywhere. Not just in JavaScript, but also C#.
If they're missing I'll add them. If someone removes them. Hmmm... OK let's stop here for alibi purposes. :D
Oh futher reply, Michael it's not about brace or not to brace that I respect about your comment, it's that you have a good strong opinion. That is the most important part. I always say, it can be consistently good or consistently bad but atleast it's consistently changeable.
Whatever we decide is punishable by death, stick to those guns and lint, lint, lint.
Ultimately it's 31+ years of experience (and I still have SO much to learn; things change so fast in this field - .NET Core 3.0 just landed and I'm all excited), and a lot of that experience was going through pains of even little things like that that often cost us hours or days and could have been avoided with better practices, etc.
Many of my coworkers have come to learn that if I'm really insisting on something and speaking strongly in favour or against something, there's a good reason (which they may or may not understand yet, depending on their level of experience). I'll sometimes fill them in on horror stories while having a cold beer at a nearby restaurant. :)
In our project we have a linter which won't let you commit unless you fix your code. It's a sure fire way of getting everyone to behave the same way, because that is all it's really about.
Can you tell me what tools you are using for linting? That would be useful to us since we have been bringing in new people on board (I've been on this project less than three months, some less and new one coming in soon), all with various levels of experience.
Sure, let's see, first sass-lint, that fails in CDCI, then we have es-lint with the Airbnb preset (it's a good one) we extended it and turned off a couple of js features that we don't transpile for per reasons. Lastly we have a strange stack with an equally odd templating language which is domain specific, so I adapted htmlhint with some custom rules to lint that (proud). Not all of the linting is switched on to fail CDCI yet and only JavaScript has a commit hook tool. The hook tool is quite new so I don't know the name but I will find out and get back to you.
Cool stuff, I'll look into that. Thanks! :)
I would be very interested in a link to whomever it is that doesn't recommend omitting semicolons. Is it ECMAScript? Is it a general consensus that I can find somewhere? Or is it a personal preference?
Can you provide some examples in which this is the case?
I'm not trying to challenge your point, I am honestly interested in the semicolon debate. It's just that I've never seen any compelling reason to use them.
The point is to understand where automatic semicolon insertion is going to cause bugs and avoid code that will allow it (preferably with lint rules) and then be consistent. The classic example is to avoid a
return
statement that splits the returned value to a new line.Anyway I'll add a sixth best practice you should always follow:
Never follow advice that says you should always follow it. There are always exceptions :)
To the first part, this is the official styling guide by google
here
Note that ECMA Script does not force you to explicitly type semicolons. It does not recommend relying on ASI either.
To the second part, I might have to dig up some examples, but in general writing codes passing function expressions as parameters, object literals as parameters, and nested function calls can get pretty messy and even if pretified, without semicolons denoting end of statements, it is hard to follow code.
Google is Google it is not the overarching authority on JavaScript style. You are better placed following the lint rules of your project. ASI works but knowing where to put semi's is the problem for some people. I use semi because I follow my project nfr's, I used to omit them, now I don't care and I recommend both ways. They both work fine.
But that's just a style guide to ensure that Google code follows the same conventions all throughout. It seems to me far from any sort of official/widely agreed on recommendation. In fact, if we were to take the document's guidelines as best practices, it clearly contradicts your last point.
Maybe if the code is very messy. Personally I've never had trouble with those. Well, at least not any trouble that I thought would be solved or improved by adding semicolons.
For some additional information on whether you should / shouldn't rely on ASI, check out this post!
This is a great post, Umer, both for beginners & experienced devs.
As someone who comes from a c++/c# background, I find myself creating a few globals e.g βSite titleβ, βAuthorβ and other meta-tags. Will be trying out your suggestions now π
This is a neat post. Here are some of my initial takeaways:
While I agree with you that you should not rely on ASI, it's really all up to whomever is writing the code. A lot of other people have pointed out that just because Google's style guide dictates that you should not rely on ASI doesn't mean that it is now written in stone. For some more information on why you should / shouldn't use ASI, check out this read for more information. It has a lot of good points, and only helped to reinforce the reasoning behind why I do not use ASI.
Any piece of code? You mentioned that even if you only use a snippet twice, you should function-ify it. While I'm all for cutting down on code re-use, if we were to abstract every segment of code away into functions... Well, now, what would that do for your program's readability? π€
I tend to agree with this one as well, but with a huuuuuuuuge caveat: keeping your code consistent is as important, if not more, than keeping your code concise. You mention removal of the brackets as one way to help improve readability and limit redundancy.
Humans, however, have a much easier time reading when there are detectable patterns (consistent use of brackets is a good example of this). When you do not follow a pattern, reasoning about the code becomes decidedly more difficult. While I have other opinions about keeping
if
statements on one line, I almost always use the optional curly brackets. I would argue that omitting the curly brackets does little to improve readability. Often times, I would argue the inverse πOn the whole, while I certainly agree that a lot of these concepts are important to learn, only some of them pertain directly to Javascript. Things like abstracting reused code into functions and keeping things concise and consistent are just best practices when it comes to programming at large.
Strong disagree with 2, 3, and 5.
Code is for humans. Readability is above all.
Concise code != Readable code
There will be times when a for loop is easier to read than a higher order array method.
For instance, handling async code within a map or reduce is far more difficult to read than a loop.
Very rarely will the lack of semicolons cause bugs or unwanted side-effects. Several linters and code editors can be configured to highlight exceptions.