// Guess what this function does? function createMenu() { const menuWrap = document.createElement('ul'); const itemHome = document.createElement('li'); itemHome.textContent = 'Home'; itemHome.className = 'menu-item menu-item--active'; menuWrap.appendChild(itemHome); const itemAbout = document.createElement('li'); itemAbout.textContent = 'About'; itemAbout.className = 'menu-item'; menuWrap.appendChild(itemAbout); /* more items... */ menuWrap.addEventListener('click', (event) => { const target = event.target; // handle menu item click... }); const logo = document.getElementById('logo-wrap'); logo.parentElement.insertAfter(menuWrap, logo); }
// Guess what this function does? function createMenu() { const menuWrap = document.createElement('ul'); const itemHome = document.createElement('li'); itemHome.textContent = 'Home'; itemHome.className = 'menu-item menu-item--active'; menuWrap.appendChild(itemHome); const itemAbout = document.createElement('li'); itemAbout.textContent = 'About'; itemAbout.className = 'menu-item'; menuWrap.appendChild(itemAbout); /* more items... */ menuWrap.addEventListener('click', (event) => { const target = event.target; // handle menu item click... }); const logo = document.getElementById('logo-wrap'); logo.parentElement.insertAfter(menuWrap, logo); }
<!-- Here's what we SHOULD write instead --> <header> <ul class="menu"> <li class="menu-item menu-item--active" click="handleItemClick(event)"> Home </li> <li class="menu-item" click="handleItemClick(event)"> About </li> <!-- more items... --> </ul> </header> <script> function handleItemClick(event) { var target = event.currentTarget; // handle menu item click... } </script>
<!-- Here's what we SHOULD write instead --> <header> <ul class="menu"> <li class="menu-item menu-item--active" click="handleItemClick(event)"> Home </li> <li class="menu-item" click="handleItemClick(event)"> About </li> <!-- more items... --> </ul> </header> <script> function handleItemClick(event) { var target = event.currentTarget; // handle menu item click... } </script>
// Guess what this function does? function createMenu() { const menuWrap = document.createElement('ul'); const itemHome = document.createElement('li'); itemHome.textContent = 'Home'; itemHome.className = 'menu-item menu-item--active'; menuWrap.appendChild(itemHome); const itemAbout = document.createElement('li'); itemAbout.textContent = 'About'; itemAbout.className = 'menu-item'; menuWrap.appendChild(itemAbout); /* more items... */ menuWrap.addEventListener('click', (event) => { const target = event.target; // handle menu item click... }); const logo = document.getElementById('logo-wrap'); logo.parentElement.insertAfter(menuWrap, logo); }
// Guess what this function does? function createMenu() { const menuWrap = document.createElement('ul'); const itemHome = document.createElement('li'); itemHome.textContent = 'Home'; itemHome.className = 'menu-item menu-item--active'; menuWrap.appendChild(itemHome); const itemAbout = document.createElement('li'); itemAbout.textContent = 'About'; itemAbout.className = 'menu-item'; menuWrap.appendChild(itemAbout); /* more items... */ menuWrap.addEventListener('click', (event) => { const target = event.target; // handle menu item click... }); const logo = document.getElementById('logo-wrap'); logo.parentElement.insertAfter(menuWrap, logo); }
<!-- Here's what we SHOULD write instead --> <header> <ul class="menu"> <li class="menu-item menu-item--active" click="handleItemClick(event)"> Home </li> <li class="menu-item" click="handleItemClick(event)"> About </li> <!-- more items... --> </ul> </header> <script> function handleItemClick(event) { var target = event.currentTarget; // handle menu item click... } </script>
<!-- Here's what we SHOULD write instead --> <header> <ul class="menu"> <li class="menu-item menu-item--active" click="handleItemClick(event)"> Home </li> <li class="menu-item" click="handleItemClick(event)"> About </li> <!-- more items... --> </ul> </header> <script> function handleItemClick(event) { var target = event.currentTarget; // handle menu item click... } </script>
const req = new XMLHttpRequest(); req.addEventListener('load', function () { if (request.status >= 200 && request.status < 400) { // Success! var data = JSON.parse(request.responseText); } else { // We reached our target server, but it returned an error } }); req.addEventListener('error', function () { // There was a connection error of some sort }); req.open('GET', 'http://www.example.org/example.json'); req.setRequestHeader('Content-Type', 'application/json'); req.setRequestHeader('Authorization', 'Bearer abc123xyz456'); req.send();
const req = new XMLHttpRequest(); req.addEventListener('load', function () { if (request.status >= 200 && request.status < 400) { // Success! var data = JSON.parse(request.responseText); } else { // We reached our target server, but it returned an error } }); req.addEventListener('error', function () { // There was a connection error of some sort }); req.open('GET', 'http://www.example.org/example.json'); req.setRequestHeader('Content-Type', 'application/json'); req.setRequestHeader('Authorization', 'Bearer abc123xyz456'); req.send();
fetch('http://www.example.org/example.json', { method: 'GET', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ...' }, }).then((res) => { // check status and handle response body return res.json(); }).then((res) => { // receive the response body }).catch((err) => { // handle connection errors })
fetch('http://www.example.org/example.json', { method: 'GET', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ...' }, }).then((res) => { // check status and handle response body return res.json(); }).then((res) => { // receive the response body }).catch((err) => { // handle connection errors })
From Wiki:
"Declarative programming is
in which programs
without explicitly listing commands or steps that must be performed."
let sum = 0; for (let i = 0; i < arr.length; i++) { const item = arr[i]; const value = item.value; if (value % 2 === 0) { sum += value; } } console.log(sum);
let sum = 0; for (let i = 0; i < arr.length; i++) { const item = arr[i]; const value = item.value; if (value % 2 === 0) { sum += value; } } console.log(sum);
Instead of
for (let i = 0; i < arr.length; i++) { const item = arr[i]; // iterate an array and do something }
for (let i = 0; i < arr.length; i++) { const item = arr[i]; // iterate an array and do something }
let sum = arr.map((item) => item.value) .filter((value) => (value % 2 === 0)) .reduce((acc, value) => acc + value, 0); // Note: `reduce` is not always readable // and should use with care
let sum = arr.map((item) => item.value) .filter((value) => (value % 2 === 0)) .reduce((acc, value) => acc + value, 0); // Note: `reduce` is not always readable // and should use with care
Use the Array methods
Array.from() array.forEach() array.map() array.filter() array.reduce() array.every() array.some() array.flat()
Array.from() array.forEach() array.map() array.filter() array.reduce() array.every() array.some() array.flat()
Object creation
var user = new Object(); user.name = 'Nguyen Van A'; user.age = 20; user.gender = 'male'; user.address = '1 Le Duan'; user.tempAddress = '2 Ngo Duc Ke';
var user = new Object(); user.name = 'Nguyen Van A'; user.age = 20; user.gender = 'male'; user.address = '1 Le Duan'; user.tempAddress = '2 Ngo Duc Ke';
Some time later:
user.maritalStatus = 'single'; // new properties user.age = 21; // update properties delete user.tempAddress; // delete properties
user.maritalStatus = 'single'; // new properties user.age = 21; // update properties delete user.tempAddress; // delete properties
Object creation with literals
const user = { name: 'Nguyen Van A', age: 20, gender: 'male', address: '2 Ngo Duc Ke', tempAddress: '2 Ngo Duc Ke', }
const user = { name: 'Nguyen Van A', age: 20, gender: 'male', address: '2 Ngo Duc Ke', tempAddress: '2 Ngo Duc Ke', }
Declarative promote immutability:
const { tempAddress, ...oldUser} = user; const newUser = { ...oldUser, age: 21, maritalStatus: 'single', // tempAddress is not available in newUser }
const { tempAddress, ...oldUser} = user; const newUser = { ...oldUser, age: 21, maritalStatus: 'single', // tempAddress is not available in newUser }
We can improve object update ergonomics a bit with Immer.js but it come with a cost
Avoid undefined pointer using condition:
let value; if (data && data.person && data.person.address) { value = data.person.address.streetName; }
let value; if (data && data.person && data.person.address) { value = data.person.address.streetName; }
Promise*:
function getData() { let data; fetch('url') .then((res) => res.json()) .then(json => data = json) .catch((err) => { // handle error }) }
function getData() { let data; fetch('url') .then((res) => res.json()) .then(json => data = json) .catch((err) => { // handle error }) }
* it is still inperative from some aspects
Optional chaining
const value = data?.person?.address?.streetName; //
const value = data?.person?.address?.streetName; //
Async / await
async function getData() { let data; try { const response = await fetch('/my/url'); data = await response.json(); } catch (err) { // handle errors } }
async function getData() { let data; try { const response = await fetch('/my/url'); data = await response.json(); } catch (err) { // handle errors } }
var $ = jQuery; function createMenu() { var $menu = $.html( `<ul id="menu" className="menu"> <li data-menu="home" className="menu-item">Home</li> <li data-menu="about" className="menu-item">About</li> </ul>`); $('#header').append($menu); } function updateActive(activeItem) { $('#menu > li') .removeClass('menu-item--active') .filter('[data-menu="' + activeItem + '"]') .addClass('menu-item--active'); }
var $ = jQuery; function createMenu() { var $menu = $.html( `<ul id="menu" className="menu"> <li data-menu="home" className="menu-item">Home</li> <li data-menu="about" className="menu-item">About</li> </ul>`); $('#header').append($menu); } function updateActive(activeItem) { $('#menu > li') .removeClass('menu-item--active') .filter('[data-menu="' + activeItem + '"]') .addClass('menu-item--active'); }
const Menu = ({active}) => { return ( <ul className="menu"> <li className={classes({ 'menu-item' : true, 'menu-item--active': active === 'home' })}> Home </li> <li className={classes({ 'menu-item' : true, 'menu-item--active': active === 'about' })}> About </li> </ul> ) };
const Menu = ({active}) => { return ( <ul className="menu"> <li className={classes({ 'menu-item' : true, 'menu-item--active': active === 'home' })}> Home </li> <li className={classes({ 'menu-item' : true, 'menu-item--active': active === 'about' })}> About </li> </ul> ) };
⚠️ Some considerations:
Bonus: Declarative object literals in modern JS