Always “use strict” On
Use Function expressions instead of Function Declarations
Unless you want to take advantage of Function behavior and properties, prefer function expressions. Function declarations are hoisted and although it can be useful sometimes, avoid them as they introduce weird behavior to the code and it is not always obvious what's happening. Try to make it clear where the function you are using comes from and they come before you use them to avoid weird access.
Stop using “var”!
Declarations with “var” are also hoisted which makes var declarations be accessible before where the declaration happened which is weird, non-obvious behavior.
Use “const” and immutability as much as possible
Prefer immutability as much as possible. Constantly changing data and passing it around can make it hard to track bugs and the changes itself. Work on data copies and avoid side effects.
Prefer Pure Functions
Continuing on the side effect note, ensure your functions are not changing data they are called with or data in the scope where they are created.
Prefer Class over Constructor Functions
Although the constructor function allows you to do some very nice stuff, if you find yourself reaching out for its prototype is a sign you need to use “class” which are supported pretty much anywhere. It is cleaner and something people are more likely to understand.
Destructuring is elegant and makes it more obvious what you need from array and objects and also gives you the opportunity to rename things to help give more sense to your code.
Only work with data you need
Like the above examples, destructuring is a good way to extract the data you need to do the job but, also make it a habit to only call methods and functions with the things they need. This also goes to the data coming from the API. Extract and cleanup only the data you need before storing or doing anything to it.
Always use “===”
The triple equal checks for value and type and it is something you always want to do. Make it a habit to always triple check and avoid undesirable effects.
Avoid Global Variables
Avoiding creating things in global objects unless you are creating a library/framework. Global property names may collide with third parties or something a colleague also introduced and are hard to debug.
Wrap loose declarations in blocks
You can avoid name clash and loose temporary declarations access by wrapping a quickly logic in its own scope.
Organize your declarations
Be consistent with the way you declare things. Put all your declarations on top starting with the constants down to the variables. Make constants all uppercase to indicate they are constants which will prevent devs from trying to change them.
Don't initialize things with “undefined”
Always initialize your declarations
For the same reason, you should not give “undefined” as a value to declarations, you should not leave them without a value because they are “undefined” by default.
Lint your code and have a consistent style
Linting your code is the best way to ensure a consistent look and feel of your code and make sure people don't do weird things to it as well. It puts everyone on the same page.
Typescript can help you a lot in delivering better code. It will need some getting used to if you never tried a type system but it pays off in the long run.
Functions and methods should do one thing only
It is easy to get carried away with adding extra stuff to function while you are at it and the best way to find out whether a function is doing too much is by looking at its name. The name should tell what the function does and anything unrelated should go.
Don’t be lazy when naming things
Always put some effort into naming things. If it is hard to name you probably gave it extra responsibility or do not understand what it is. Give it at least a 3 letter name with meaning.
Avoid unnecessary declarations
Some declaration can be avoided altogether so only declare when it is strictly necessary. Too many declarations may hint at a lack of proper code design or declaration consideration
Use default values when posible
Always have a default case for switch statements
Don't leave your switch statements without a default case because something can go wrong and you want to make sure you catch it.
Never use “eval”
Never! It is not necessary.
Avoid the “new” keyword
Except for class and constructor functions instancing, you should never use the “new” keyword for anything else. They can slow compilers down.
Add meaningful comments for nonobvious things
Only add comments when you did something not common, weird, or requires context to be understood. Also, add comments to things that are a hack or may require improvements/fixing later on so the next person knows why. Add comments in your third parties' modules and modules in your codebase to explain the architecture and the intention behind things.
Keep ternaries simple
Worst case scenario you have two nested ternaries. Anything longer should be an if statement or switch for readability and easy to debug reasons.
Simplify with optional chaining
Get rid of those nested checks and use the “?” Operator.
Prefer promises over callbacks
For loops > .forEach sometimes
Don't change things into an array just so you can “.forEach” it. You are adding extra process to a slow alternative. For loops are faster and allows you to use the “continue” and “break” keywords to control the looping.
“for…in” and “for…of”
The for-in and for-of loops are very powerful ways to loop. The “for-of” loop lets you go over the values of the array, strings, Map, Set, etc. No need to change something into an array to use .forEach. I would avoid the “for-in” for looping as it is the slowest one and iterates over prototype keys.
Optimize for loops?
For loops are already optimized by the compiler so no need for that kinda of optimization.
Always “try…catch” JSON methods
Don't trust things passed to JSON methods “.stringify” and “.parse”. Try to catch them to make sure they don't fail and break your code.
Prefer template strings
It is that simple. Template strings allow you to inject values into the string and they keep the format that can come in handy.
Avoid nesting or chaining loops
When you chain iteration method or nest loops you are increasing the complexity of the code which may slow things down later on or as your data grows. Even though some operations may require it, always assess your looping strategy to ensure you don’t have unnecessary loops or loops that can be combined together.
Avoid Weird Unreadable hacks
They are all over the internet because people find them “cool”. They are usually weird, non-conventional, and non-obvious when you look at them. It is always best to follow the guidelines of the tool you are using to ensure proper performance. Hacking should be that last alternative.
Prefer the “rest” operator over “arguments”
The “rest” operator will work with arrow functions where “arguments” are not available. Stick to one way to access your function arguments.
Prefer “globalThis” for global access
Add semicolons, always!
Readable > Performance unless you need Performance
There are ways to get more performance by doing things that are often hard to read but unless you are desperate for performance at the code level (which is rare), make it readable.
Be careful with “Truthy” and “Falsy” checks
Prefer Ternary over logical “||” and “&&” checks
The “or” and “and” operators evaluates the “true” and “false” of a value which may result in undesired results. Also, don’t rely on it to do weird logical condition checks as they are not readable and easy to understand.
Watch out for “undefined” and “null” with the “??” operator
The nullish coalescing operator makes sure that null and undefined values are not picked and it is perfect for cases where you want to ensure that there is a value or fallback to a default value.
Be careful with automatic type conversions
Never trust data you don't create
Whenever you are dealing with data coming from a user or from an API you don't know, make sure it is of the right type and in a format that you can work with before you do any operation on it.
Use regex when extracting and looking for things in Strings
Regex is super powerful and fun. Avoid weird manipulation like looking for indexes and grabbing things. Regex allows you to look for complex patterns and
IIFE and small utility libraries
IIFE is an excellent way to execute things as early as possible which you can take advantage of to set up some stuff before the rest of the code starts running. You can also use it to initialize small libraries with a simple API that allows you to encapsulate some complex logic and expose an object you can use to interact with similar to how jQuery is built.
Avoid repeating yourself with utilities
Always turn things you do repeatedly into small generic functions that you can reuse later on. As a developer, you should not be repeating things and small functions make them easy to test and reuse.
Things like updating array length property, using the “with” keyword, void keyword, updating native Object prototypes like Date, Array, Object, etc. Others like passing a string to setTimeout and setInterval. Just because the language allows you to, does not mean you should.
Add Unit Tests
As a developer, I often found bugs when I started adding unit tests. Tests are the ultimate way to ensure that your code as error-free as possible. Jest is an excellent option to start with but there are others out there that are also as simple to use.
For video examples check: