HTML and CSS are declarative, JavaScript is imperative - that's the main reason why you should prefer HTML and CSS.
Any imperative code is a hard to maintain, so first of all, try make code readable and easy to understand
The same as similar tip from CSS
This allows your site to show first content without blocking on code execution
This will allow you to write applications with better performance and avoid a lot of mistakes while working with native DOM API. The good explanation is here
Some users prefer to submit form with hitting Enter button inside the last input or pressing the Space button on <input type="submit" />
Avoid instruction with more than 1 operator inside if
conditions. Move such a code (allowUpdate) && ((user.isAdmin) || (user.role === item.owner)
to the separate function like isAdminAndCanUpdate
Of course, sometimes it is a good move - to extend String.prototype
or Function.prototype
but extend it only with standard functions used widely. For example, you can create polyfill for Function.prototype.bind
if you know very good what you are doing
Usually .map(...)
, .filter(...)
, .reduce(...)
methods are more readable than simple for
and while
loops. Additional advantage is the ability to export iterator-function separately and use it many times in different modules
if (status === 'active') {...}
- this is bad
if (status === constants.ACTIVE_STATUS) {...}
- this is correct
Use Modernizr for feature detection
Don't hope that comparing with user-agent is a better idea
Global variables make the application unpredictable. Global variables have a too spread area of usage. Global variables make the app overcomplicated. Of course sometimes life makes us use global variables, here is the list of examples:
- Oldschool libraries like Google Maps - it creates global variable itself. It also requires global callback function to notify us when everything is ready.
- Importing modules in small jQuery projects - here we can create one global variable to save all modules there
We should outstand all global variables and window
prefix is great for this. It also helps us to find all usage among all project files
// bad example:
function test () {
foo = 'hello world'; // variable was created without var, so it is global
}
test();
console.log(foo) // use foo as not window propery
// correct example:
function test () {
window.foo = 'hello world'; // here foo is explicit window property
}
test();
console.log(window.foo) // use foo also as window property
Sometimes it is good practice to produce some logs in production - but keep your debug warnings away from end users
var el = document.getElementById(id);
// avoid such code
el.style.color = "red";
el.style.fontSize = "15px";
el.style.backgroundColor = "#FFFFFF";
// use such approach
el.classList.add("outstanding-text")
Don't rely on classes that you also use for styling, sometimes you will change them because you will need new appearance. With such action, you will break the scripts also! This tip will save you from double event handlers or outdated listeners
<div class="open-popup-button js-open-popup-button"></div>
In js-files you will only use second class:
$('.js-open-popup-button').click(...);
If there is no need to search elements again - cache results into the variable
// this is bad
$('.element').show();
$('.element').find('.children').doSomething();
$('.element').attr('data-id', 123);
// this is correct
var $element = $('.element');
$element.show();
$element.find('.children').doSomething();
$element.attr('data-id', 123);
var $element = $('.element');
var $this = $(this);
var $lists = $body.find('ul');
var chatBox = document.getElementById('chat-box'); // because it is native DOM element
var firstList = $lists[0]; // because it is also native DOM element
// bad way
$('form p').addClass('valid');
$('form li').addClass('valid');
$('form span').addClass('valid');
// good way
$('form p, form li, form span').addClass('valid');
When you need to add multiple elements in the DOM - create virtual parent and inject element there. When all work is done you can inject only one parent in the DOM with one instruction:
// bad way, we inject each element separately
for (var i=0; i < items.length; i++){
var item = document.createElement("li");
item.appendChild(document.createTextNode("Option " + i);
list.appendChild(item);
}
// good way - we gather all element in the virtual Fragment before appending to the list
var fragment = document.createDocumentFragment();
for (var i=0; i < items.length; i++){
var item = document.createElement("li");
item.appendChild(document.createTextNode("Option " + i);
fragment.appendChild(item);
}
list.appendChild(fragment);
If you need to change the library critically - fork it on Github and define new version as dependency (e.g. in package.json
)
When you need to add new feature to your project (for example new pretty dropdown or URL routing) it is good choice to use some library. Usually they are tested and written much better than your own possible decision. Although it is hard for newbies to find out that library has bad code and choose the best when there is a bunch of choices. Check for each option:
- Is there a public repository and where is it?
- Is there a documentation and does it describe how to solve your problem exactly?
- If there is no detailed documentation, learn a source code and understand how it solves your problem
- Learn last issues - does it relate to your problems?
- If there are other front-end developers working on the same project, make decision together.
Always divide your app into modules. Try to make modules with strong cohesion and weak coupling.
Try to make all module structures among the whole project explicitly and monotonously. Separate all DOM manipulations, managing application state and data fetching from an API server. Make the convention about typical module structure and follow it
Try to group all methods by their meaning
Consider following code:
var box = {};
function addBall(box) {
box.ball = {radius: 2};
}
function addFood(box) {
box.food = {carrot: 4};
}
function addShoes(box) {
box.shoes = {sneakers: 2};
}
addBall(box);
addFood(box);
addShoes(box);
Here we have to expand area of usage for variable box
. In greater apps that use such patterns we will be confused why some vars eventually have dozens of carrots and thousands of shoes :)