Table of content
- Avoid global variables as much as possible
- Code attribution/ plagiarism
- OOP versus functional approach
- Using InnerHTML
- Cache elements in variables
- Split fetch url in separate chunks
- Keep functions simple and focused
- Waterfall 🌊 vs. Returning Values 🎁
- DRY
- var, let or const?
- for versus forEach
- Avoid inline CSS in JavaScript
- Loading external script files
- Handle loaded state in .finally()
- Object destructuring
Global variables can cause conflicts and thus errors..
- You're allowed to use code you found online (unless its license mentions otherwise)
- You should always credit the creator and source of used code
- For important pieces of code, include them in the acknowledgements at the bottom of your readme.
- For ALL code you haven't written, include the source in a comment right above the line where you use the code.
- If you base a project off of someone else's project, mention it explicitly in the code at the top of your file as well as in the readme.
- You're allowed to commit to either strategy.
- Here's a nice example of an OOP web app. Notice how object are responsible and self contained. Also notice how you need to jump through the code a lot in order to follow the flow of control.
- Tomas went for a more functional approach. Here it's easier to chain functionalities together and the code reads more like human language.
- InnerHTML is not safe when you're overwriting the entire html content of a node [citation needed]
- Use
Element.insertAdjacentHTML()
if you need to insert the resulting nodes into the DOM tree at a specified position - Don't pick an alternative because you saw it being used somewhere, read up on the differences and make an informed decision.
For readability and efficient code. Only one lookup is needed when the element is stored in a variable.
Good:
const el = document.querySelector('...');
el.classList.toggle('...');
Bad:
document.querySelector('...').classList.toggle('...');
For readability and efficient code. With this aproach parts of the url can be reused for future fetches.
Good:
const cors = 'https://cors-anywhere.herokuapp.com/';
const endpoint = 'https://api.anywhere.com';
const key = '42';
const url = `${cors}`${endpoint}/?key=${key};
fetch (url)
Bad:
fetch('https://cors-anywhere.herokuapp.com/https://api.anywhere.com?key=42');
Or even better, take a look at the URL API:
MDN URL
Give functions one clear goal for better redability and reusability
Functions and the Single Responsibility Principle
There are multiple ways of writing code, however that doesn't make this readable for everyone. Check this waterfall instance.
app.js module (main module)
import {cleanData} from 'clean.js'
function getData (){
fetch('url',{})
.then(res=>cleanData(res))
}
getData()
clean.js module
import {renderData} from 'render.js'
function cleanData (uncleanData){
// clean data
renderData(cleanedData)
}
// The Waterfall
// getData() -> cleanData() -> renderData()
This piece of code requires you to search through multiple files and you're actually rendering with the getData
function. This makes bug fixing and maintaining this way harder than it needs to be since it's unclear what is happening and where.
Instead it would be more efficient and readable if you let the functions return its values. You should always aim to make your code readable so that another developer can see what's happening in an instant.
app.js module (main module)
import {getData} from 'fetcher.js'
import {cleanData} from 'clean.js'
import {renderData} from 'render.js'
function init async(){
const data = cleanData(await getData())
renderData(data)
}
init()
fetcher.js module
//
function getData (){
// clean data
return new Promise((resolve,reject)=>{
fetch('url',{})
.then(res=>resolve(res))
})
}
Make your code read like a book instead of the worst Ikea manual.
Don't repeat yourself!
For efficient and readable code.
Know when to use which assignment identifier. Be consitent and try to make the most logical choices for your code.
JavaScript ES6+: var, let, or const?
In most cases a forEach loop is a better choice for looping through an array(like object).
forEach vs for Loops in JavaScript: What's the Difference?
Good:
const el = document.querySelector('...');
el.classList.toggle('...');
Bad:
const el = document.querySelector('...');
el.style.display('none');
For dynamic styling consider using custom properties, passing only data from JavaScript to CSS. It's Time To Start Using CSS Custom Properties
Example:
element.style.setProperty(`--varName`, value)
Load external script files in the tail of the body
element. Giving all DOM elements a chance to load before JavaScript kicks in.
You can also use asyn/defer attributes if you're feeling dandy!
Asynchronous vs Deferred JavaScript
state('loading')
return fetch(url)
.then(response => response.json())
.then(data => clean(data.data))
.then(data => store(data))
.catch(err => {
state(err)
})
.finally(()=> {
state('loaded')
})
Use object destructuring for better readability
Ok:
function render(data) {
const section = $("section")
data.forEach((item) => {
const html = `
<article>
<a href="#gifs/${item.id}">
<h3>${item.title}</h3>
<img src="https://media.giphy.com/media/${item.id}/giphy.gif">
<p>${item.description}</p>
</a>
</article>
`;
section.insertAdjacentHTML('beforeend', html)
})
}
Good:
function render(data) {
const section = $("section")
data.forEach((item) => {
const { id, title, description } = item
const html = `
<article>
<a href="#gifs/${id}">
<h3>${title}</h3>
<img src="https://media.giphy.com/media/${id}/giphy.gif">
<p>${description}</p>
</a>
</article>
`;
section.insertAdjacentHTML('beforeend', html)
})
}
Or:
function render(data) {
const section = $("section")
data.forEach(({ id, title, description }) => {
const html = `
<article>
<a href="#gifs/${id}">
<h3>${title}</h3>
<img src="https://media.giphy.com/media/${id}/giphy.gif">
<p>${description}</p>
</a>
</article>
`;
section.insertAdjacentHTML('beforeend', html)
})
}