Javascript snippets, tricks and tips
Bitwise in Javascript
Setting bitwise attributes
const attrA = 1 << 0; // 2^0 i.e. 0001
const attrB = 1 << 1; // 2^1 i.e. 0010
const attrC = 1 << 2; // 2^2 i.e. 0100
const attrD = 1 << 3; // 2^3 i.e. 1000
let flags = 0; // empty
// use | to add attributes
flags = flags | attrA; // or flags |= attrA
// 1 - i.e. 0000 | 0001 -> 0001
flags = flags | attrC;
// 5 - i.e. 0001 | 0100 -> 0101
// use ^ to remove attributes
flags = flags ^ attrA; // or flags ^= attrA;
// 4 - i.e. 0101 ^ 0001 -> 0100
Checking for attributes
Four possible cases:
// has a single attribute attrA - "&" is exclusionary
if (flags & attrA) {}
// has ANY of the attributes - "|" is inclusionary, "&" is exclusionary
if (flags & (attrA | attrC)) {}
// ^^^^^^^^^^^^^^^^^^^^^^ evaluates to a value >= 0
// has ONLY the specified attributes
if (flags === (attrA | attrC)) {}
// ^^^^^^^^^^^^^^^^^^^^^^^ evaluates to a boolean
// has ALL of the attributes
// i.e. the union of attributes can't supersede the flags alone, otherwise it
// has a bit that flags doesn't
if (flags === (flags | (attrA | attrC))) {}
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluates to a boolean
Refs
- https://codeburst.io/using-javascript-bitwise-operators-in-real-life-f551a731ff5
- https://www.w3schools.com/js/js_bitwise.asp
Calculate day of year
const now = new Date()
const start = new Date(now.getFullYear(), 0, 0)
const diff = (now - start) + ((start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000);
const oneDay = 1000 * 60 * 60 * 24
const day = Math.floor(diff / oneDay)
console.log('Day of year: ' + day)
Check if an array is not empty
const isNotEmpty = (arr) => Array.isArray(arr) && Object.keys(arr).length > 0;
// Examples
isNotEmpty([]); // false
isNotEmpty([1, 2, 3]); // true
Objects
Check if an element is focused
const hasFocus = (el) => el === document.activeElement
Check if an object is a Promise
const isPromise = (obj) =>
!!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';
Check if an object is an array
const isArray = (obj) => Array.isArray(obj);
Check if multiple objects are equal
const isEqual = (...objects) => objects.every((obj) => JSON.stringify(obj) === JSON.stringify(objects[0]));
// Examples
isEqual({ foo: 'bar' }, { foo: 'bar' }); // true
isEqual({ foo: 'bar' }, { bar: 'foo' }); // false
Clear all cookies
const clearCookies = () => document.cookie
.split(';')
.forEach(c =>(document.cookie = c.replace(/^ +/, '').replace(/=.*/, `=;expires=${new Date().toUTCString()};path=/`)))
Compare two arrays
// `a` and `b` are arrays
const isEqual = (a, b) => JSON.stringify(a) === JSON.stringify(b);
// Or
const isEqual = (a, b) => a.length === b.length && a.every((v, i) => v === b[i]);
// Examples
isEqual([1, 2, 3], [1, 2, 3]); // true
isEqual([1, 2, 3], [1, '2', 3]); // false
Convert an array of objects to a single object
const toObject = (arr, key) => arr.reduce((a, b) => ({ ...a, [b[key]]: b }), {});
// Or
const toObject = (arr, key) => Object.fromEntries(arr.map((it) => [it[key], it]));
// Example
toObject([
{ id: '1', name: 'Alpha', gender: 'Male' },
{ id: '2', name: 'Bravo', gender: 'Male' },
{ id: '3', name: 'Charlie', gender: 'Female' }],
'id');
/*
{
'1': { id: '1', name: 'Alpha', gender: 'Male' },
'2': { id: '2', name: 'Bravo', gender: 'Male' },
'3': { id: '3', name: 'Charlie', gender: 'Female' }
}
*/
Convert cookie to object
const cookies = document.cookie.split(';').map((item) => item.split('=')).reduce((acc, [k, v]) => (acc[k.trim().replace('"', '')] = v) && acc, {})
Count by the properties of an array of objects
const countBy = (arr, prop) => arr.reduce((prev, curr) => ((prev[curr[prop]] = ++prev[curr[prop]] || 1), prev), {});
// Example
countBy([
{ branch: 'audi', model: 'q8', year: '2019' },
{ branch: 'audi', model: 'rs7', year: '2020' },
{ branch: 'ford', model: 'mustang', year: '2019' },
{ branch: 'ford', model: 'explorer', year: '2020' },
{ branch: 'bmw', model: 'x7', year: '2020' },
],
'branch');
// { 'audi': 2, 'ford': 2, 'bmw': 1 }
Destructuring in Javascript
Skip items from an array
const array = [9, 8, 7, 6, 5]
const [a, , b] = array
Using rest
parameter
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9]
const [a, b, ...c] = array
console.log(a) // 1
console.log(b) // 2
console.log(c) // [3, 4, 5, 6, 7, 8, 9]
Swap variable values without temp var
let a = 1
let b = 2
let [b, a] = [a, b]
Destructure return value of a function
const [a, b] = data()
const { name, role } = data()
Set default values (also works for Objects)
const [a, b=2] = array
const { first, second='two' } = object
Get data from an object (also with the rest
parameter)
const user = {
name: 'Seumas',
role: 'bobby',
patrolling: true,
sailing: true,
}
const { name, role, ...hobbies } = user
console.log(hobbies) // { patrolling: true, sailing: true }
Get data from an object with DIFFERENT variable names
It is also possible to allocate different variable names:
(NOTE: the new name is the 2nd “value” element)
const user = {
name: 'Seumas',
role: 'bobby',
patrolling: true,
sailing: true,
}
const { name: namen, role: funktion, ...rest } = user
console.log(namen) // Seumas
console.log(funktion) // bobby
Destruct a function parameter
function ({ name, email, roles }) {
console.log('Name', name)
console.log('Email', email)
console.log('Roles', roles)
}
Extract values of a property from an array of objects
const pluck = (objs, property) => objs.map((obj) => obj[property]);
// Example
pluck([
{ name: 'John', age: 20 },
{ name: 'Smith', age: 25 },
{ name: 'Peter', age: 30 },
],
'name');
// ['John', 'Smith', 'Peter']
Find key in object by its value in Javascript
Based on this posting:
let found = Object.keys(object).find(key => object[key] === value)
Find the highest zIndex value using Javascript
Based on this source - note the
trick using forEach
to iterate over a NodeList :
let max = 0
const els = document.querySelectorAll('*')
[].forEach.call(els, el => {
const zindex = document.defaultView.getComputedStyle(el,null).getPropertyValue("z-index")
max = (parseInt(zindex)>max) ? zindex: max
})
console.log(max)
Find value in object by its key in Javascript
let searching = 'ACTION'
let found = Object.keys(object)
.map(key => key === searching ? { [key]: object[key] } : false)
.find(Boolean)
Call a Javascript function conditionally
const area = () => {
console.log('area')
}
const volume = () => {
console.log('volume')
}
(type === 'square' ? area : volume)()
Generate random string
[...Array(10)].map(i=>(~~(Math.random()*36)).toString(36)).join('')
// ^^ string length required
Get all siblings of an element
const siblings = (el) => [].slice.call(el.parentNode.children).filter(child => child !== el)
Get selected text
const getSelectedText = () => window.getSelection().toString()
Go back to the previous page
history.back()
// Or
history.go(-1)
Helpful Javascript array techniques
Javascript array reduce promise pattern
let userIDs = [1,2,3];
userIDs.reduce( async (previousPromise, nextID) => {
await previousPromise;
return methodThatReturnsAPromise(nextID);
}, Promise.resolve());
Ref: https://css-tricks.com/why-using-reduce-to-sequentially-resolve-promises-works/
Looping over a NodeList in Javascript
Using Javascript array
iteration functions to loop over a NodeList
requires some special handling.
The easiest way is to use Array.from()
Array.from(document.querySelectorAll('div'))
.map(div => div.style.border = '1px solid crimson')
Older info from this source:
let divs = document.querySelectorAll('div')
[].forEach.call(divs, function(div) {
// do whatever
div.style.color = "red"
});
Array.prototype.slice
can also now do the conversion:
Array.prototype.slice.call(document.childNodes)
which can be shortened to
[].slice.call(document.childNodes)
See also here for more detail.
Remove duplicates from array in Javascript
arr.filter((val, i, self) => self.indexOf(val) === i)
Javascript equivalent of python range
function
let size = 10, startAt = 1;
[...Array(size).keys()].map(i => i + startAt);
produces
[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
or, simply for a range starting at zero
[...Array(9).keys()];
[ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]
See this posting for a more complete discussion.
Flatten an array
let arrays = [
["$6"],
["$12"],
["$25"],
["$25"],
["$18"],
["$22"],
["$10"]
]
let merged = [].concat.apply([], arrays)
console.log(merged);
The posting at https://stackoverflow.com/a/10865042 gives the following explanation:
Using the .apply()
method of .concat()
takes the second param as an array,
so the last line effectively does this:
let merged2 = [].concat(
["$6"], ["$12"], ["$25"], ["$25"],
["$18"], ["$22"], ["$10"]
)
Rotate an array
Forwards:
arr.push(arr.shift())
and in reverse:
arr.unshift(arr.pop())
Intersection of two arrays
let intersect = arr1.filter(e => arr2.includes(e))
Difference of two arrays
let diff = arr1.filter(e => !arr2.includes(e))
Invert keys and values of an object
const invert = (obj) => Object.keys(obj).reduce((res, k) => Object.assign(res, { [obj[k]]: k }), {});
// Or
const invert = (obj) => Object.fromEntries(Object.entries(obj).map(([k, v]) => [v, k]));
// Example
invert({ a: '1', b: '2', c: '3' }); // { 1: 'a', 2: 'b', 3: 'c' }
Initial capitalisation of a string
Simple function to capitalise initial character of a string
const initialCaps = string => string.charAt(0).toUpperCase() + string.slice(1)
Slugify function
Simple function to slugify a text string
const slugify = string => string.toLowerCase().replace(/\s+/g, '-').replace(/[^\w-]+/g, '')
Base64 en-/de-coding in Node.js
Encoding
Using Buffer:
let str = 'some string which needs to be encoded to base64'
let base64str = Buffer.from(str).toString('base64')
console.log({base64str})
outputs:
{
base64str: 'c29tZSBzdHJpbmcgd2hpY2ggbmVlZHMgdG8gYmUgZW5jb2RlZCB0byBiYXNlNjQ='
}
Decoding
let data = 'c29tZSBzdHJpbmcgd2hpY2ggbmVlZHMgdG8gYmUgZW5jb2RlZCB0byBiYXNlNjQ='
let str = Buffer.from(base64str, 'base64').toString('ascii')
console.log({str})
outputs:
{ str: 'some string which needs to be encoded to base64' }
Check if a directory is writable (NodeJS)
const fs = require('fs').promises
const oldfs = require('fs')
;(async () => {
let _dir = '/var'
try {
await fs.access(_dir, oldfs.constants.F_OK | oldfs.constants.W_OK | oldfs.constants.R_OK)
} catch (err) { console.error({err})}
})()
should output something like
{
err: [Error: EACCES: permission denied, access '/var'] {
errno: -13,
code: 'EACCES',
syscall: 'access',
path: '/var'
}
}
Reference: https://stackoverflow.com/a/59697728
Node.js read file using promises
const fs = require('fs').promises
let file = 'fileToRead.txt'
;(async () => {
await fs.readFile(file)
.then(data => {
/* process file contents */
})
.catch(err => console.error({err}))
})()
Promises in Javascript
Preventing complete rejection of Promise.all
in the case of individual rejections
Resolving an array of promises via Promise.all
is usually all or nothing -
it resolves with an array of resolved values once all elements resolve, or
is completely rejected with a single error as soon as a single element rejects.
The following is a workaround, catching a rejection and inserting undefined
into
the resolved array:
let promise1 = Promise.resolve(1)
let promise2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, 'foo')
})
let promise3 = new Promise((resolve, reject) => setTimeout(() => reject(3), 2000))
Promise.all(
[promise1, promise3, promise2]
.map(p => p.catch(() => undefined))
)
.then(values => console.log(values))
// outputs [ 1, undefined, 'foo' ]
Promisify the native xhr
request in Javascript
A very complete method is outlined at this source and shown below - and references an even more comprehensive discussion at MDN.
function makeRequest (method, url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open(method, url)
xhr.onload = function () {
if (this.status >= 200 && this.status < 300) {
resolve(xhr.response)
} else {
reject({
status: this.status,
statusText: xhr.statusText
})
}
}
xhr.onerror = function () {
reject({
status: this.status,
statusText: xhr.statusText
})
}
xhr.send()
})
}
which can be implemented thus
makeRequest('GET', 'http://example.com')
.then(datums => {
return makeRequest('GET', datums.url)
})
.then(moreDatums => {
console.log(moreDatums)
})
.catch(err => console.error('Augh, there was an error!', err.statusText))
Regex - accessing matched groups in Javascript
let str = "site build_version 0.3.7a";
const re = /(?:^|\s)build_(.*?)\s+(\S+)$/g;
let m = re.exec(str);
console.log(m[2]); // "0.3.7a"
See here for more detail.
Remove all null and undefined properties from an object
const removeNullUndefined = (obj) =>
Object.entries(obj)
.reduce((a, [k, v]) => (v == null ? a : ((a[k] = v), a)), {});
// Or
const removeNullUndefined = (obj) =>
Object.entries(obj)
.filter(([_, v]) => v != null)
.reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {});
// Or
const removeNullUndefined = (obj) => Object.fromEntries(Object.entries(obj).filter(([_, v]) => v != null));
// Example
removeNullUndefined({
foo: null,
bar: undefined,
fuzz: 42});
// { fuzz: 42 }
Reverse String.fromCharCode in Javascript
String.fromCharCode(224)
gives
à
The reverse is obtained thus
'à'.charCodeAt(0)
224
Shuffle an array in Javascript
function shuffle(array) {
let currentIndex = array.length, temporaryValue, randomIndex
// While there remain elements to shuffle...
while (0 !== currentIndex) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex)
currentIndex -= 1
// And swap it with the current element.
temporaryValue = array[currentIndex]
array[currentIndex] = array[randomIndex]
array[randomIndex] = temporaryValue
}
return array
}
Used like this
let arr = [2, 11, 37, 42]
arr = shuffle(arr)
console.log(arr)
Generate (co)sine function distribution values
Between 0 and 1 - useful for ease-in-out:
const easeInOutSine = n => -(Math.cos(Math.PI*n)-1)/2
Sort an object by its properties
const sort = (obj) =>
Object.keys(obj)
.sort()
.reduce((p, c) => ((p[c] = obj[c]), p), {});
// Example
const colors = {
white: '#ffffff',
black: '#000000',
red: '#ff0000',
green: '#008000',
blue: '#0000ff',
};
sort(colors);
/*
{
black: '#000000',
blue: '#0000ff',
green: '#008000',
red: '#ff0000',
white: '#ffffff',
}
*/
Strip HTML from a String in Javascript
If the HTML is well-formed,
let cleanText = strInputCode.replace(/<\/?[^>]+(>|$)/g, "")
The explanation as per this posting is as follows:
This regex looks for <, an optional slash /, one or more characters that are not >, then either > or $ (the end of the line)
Examples:
'<div>Hello</div>' ==> 'Hello'
^^^^^ ^^^^^^
'Unterminated Tag <b' ==> 'Unterminated Tag '
^^
But it is not bulletproof:
'If you are < 13 you cannot register' ==> 'If you are '
^^^^^^^^^^^^^^^^^^^^^^^^
'<div data="score > 42">Hello</div>' ==> ' 42">Hello'
^^^^^^^^^^^^^^^^^^ ^^^^^^
Another method with caveats, see this posting:
let html = '<p>Some <em>HTML</em></p>'
const div = document.createElement("div")
div.innerHTML = html
var text = div.textContent || div.innerText || '';
Tips on sorting
Sort an object property by values
Adapted from this posting:
let maxSpeed = {
car: 300,
bike: 60,
motorbike: 200,
airplane: 1000,
helicopter: 400,
rocket: 8 * 60 * 60
}
let sortable = Object
.keys(maxSpeed)
.map(vehicle => [maxSpeed[vehicle], vehicle])
sortable.sort((a,b) => b[0] - a[0]) // NB: this mutates the object sortable
// let sorted = {}
// sortable.forEach(item => sorted[item[1]] = item[0])
let sorted = sortable.reduce((acc, item) => {
acc[item[1]] = item[0]
return acc
}, {})
console.log(JSON.stringify(sorted, null, 2))
outputs
{
"rocket": 28800,
"airplane": 1000,
"helicopter": 400,
"car": 300,
"motorbike": 200,
"bike": 60
}
Truthy falsy in Javascript
Truthy and falsy in Javascript
All values in JavaScript are truthy except for those defined as falsy:
false, 0, -0, 0n, "", null, undefined, and NaN
Useful DOM related snippets in ES6 Javascript
Hide specified elements
const hide = (...el) =>
[...el].forEach(e =>
(e.style.display = 'none')
)
// e.g.
hide(document.querySelectorAll('img')) // hides all <img> elements
Check if an element has the certain class
const hasClass = (el, className) => el.classList.contains(className)
// e.g.
hasClass(document.querySelector('p.special'), 'special') // true
Toggle a class for an element
const toggleClass = (el, className) => el.classList.toggle(className);
// e.g. will remove 'special' class added in previous example
toggleClass(document.querySelector('p.special'), 'special')
Find scroll position of the current page
const getScrollPosition = (el=window) => ({
x: el.pageXOffset !== undefined ? el.pageXOffset : el.scrollLeft,
y: el.pageYOffset !== undefined ? el.pageYOffset : el.scrollTop
})
// e.g.
getScrollPosition() // can be used like this
let lastScrollPos
document.addEventListener('scroll', event => {
const report = 'Scrolled'
+ (lastScrollPos ?
' from x: ' + lastScrollPos.x + ' y: ' + lastScrollPos.y
: '')
+ ' to ' + 'x: ' + window.scrollX + ' y: ' + window.scrollY
lastScrollPos = { x: window.scrollX, y: window.scrollY }
document.querySelector('#resultOfScrollPosChange').innerHTML = report
// to output something like:
Smooth-scroll to page top
const scrollToTop = () => {
const c = document.documentElement.scrollTop || document.body.scrollTop
if (c > 0) {
window.requestAnimationFrame(scrollToTop)
window.scrollTo(0, c - c / 8)
}
}
// Example
<button onClick="scrollToTop(); return false;" />
Check if a parent element contains a specific child element
const elementContains = (parent, child) =>
parent !== child && parent.contains(child);
// e.g.
elementContains(document.querySelector('head'),
document.querySelector('title')) // true
elementContains(document.querySelector('body'),
document.querySelector('body')) // false
Determine whether an element is visible in the viewport
const elementIsVisibleInViewport = (el, partiallyVisible = false) => {
const { top, left, bottom, right } = el.getBoundingClientRect()
const { innerHeight, innerWidth } = window
return partiallyVisible
? ((top > 0 && top < innerHeight) || (bottom > 0 && bottom < innerHeight)) &&
((left > 0 && left < innerWidth) || (right > 0 && right < innerWidth))
: top >= 0 && left >= 0 && bottom <= innerHeight && right <= innerWidth
}
// Examples
elementIsVisibleInViewport(el); // (not fully visible)
elementIsVisibleInViewport(el, true); // (partially visible)
How to fetch all images within an element?
const getImages = (el, includeDuplicates = false) => {
const images = [...el.getElementsByTagName('img')]
.map(img => img.getAttribute('src'))
return includeDuplicates ? images : [...new Set(images)];
}
// Examples
getImages(document, true); // ['image1.jpg', 'image2.png', 'image1.png', '...']
getImages(document, false); // ['image1.jpg', 'image2.png', '...']
Determine whether device is mobile
const detectDeviceType = () =>
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i
.test(navigator.userAgent)
? 'Mobile'
: 'Desktop'
// e.g. the following line should show what kind of device you are using:
Get the current URL
const currentURL = () => window.location.href
Using URLSearchParams to get a page’s query string
This posting has a good demo discussion of the URLSearchParams
API
e.g.
// e.g. ?from=/
let urlParams = new URLSearchParams(window.location.search)
console.log(urlParams.has('from')) // true
console.log(urlParams.get('from')) // "/"
console.log(urlParams.getAll('from')) // ["/"]
Detect whether http or https and redirect if necessary
if (location.protocol !== 'https:') {
// this will cause a redirect
location.replace(`https:${location.href.substring(location.protocol.length)}`)
}
Convert params of a URL into an object
const getURLParameters = url => (
url.match(/([^?=&]+)(=([^&]*))/g) || []).reduce(
(a, v) => ((a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1)), a),
{}
)
// e.g.
getURLParameters('http://some.url/search?qry=javascript+tips&page=3')
// { qry: 'javascript+tips', page: '3' }
Copy a string to the clipboard
const copyToClipboard = str => {
const el = document.createElement('textarea')
el.value = str
el.setAttribute('readonly', '')
el.style.position = 'absolute'
el.style.left = '-9999px'
document.body.appendChild(el)
const selected =
document.getSelection().rangeCount > 0
? document.getSelection().getRangeAt(0)
: false
el.select()
document.execCommand('copy')
document.body.removeChild(el)
if (selected) {
document.getSelection().removeAllRanges()
document.getSelection().addRange(selected)
}
}
// e.g. clicking on the button (below) defined like this
<button
onClick="copyToClipboard('Lorem ipsum'); return false;"
>Copy 'Lorem ipsum' to clipboard</button>
// will copy the text 'Lorem ipsum' to your clipboard.
Insert a DOM element after another without using a library
Given this structure
<body>
<div class="container"></div>
</body>
let newNode = document.createElement('span')
let refNode = document.querySelector('div.container')
refNode.parentNode.insertBefore(newNode, refNode.nextSibling)
becomes
<body>
<div class="container"></div>
<span></span>
</body>
DOM document ready without jQuery
Seemingly is this a good and elegant promise-based way to achieve this.
With an HTML button
<button>wanna roar</button>
and the following Javascript:
// This is how JQuery's $.ready() works
const domReady = () => {
const readyState = document.readyState
return readyState === "interactive" || readyState === "complete" ? Promise.resolve() : new Promise((resolve) => {
return document.addEventListener("DOMContentLoaded", resolve)
})
}
const roar = () => console.log("Roar!!!")
const attachRoarHandler = () => {
return document.querySelector("button").addEventListener("click", roar)
}
domReady() // Promise only resolves when the DOM is loaded
.then(attachRoarHandler)
According to this source another option is
HTMLDocument.prototype.ready = () => {
return new Promise((resolve, reject) => {
if (document.readyState === 'complete') {
resolve(document)
} else {
document.addEventListener('DOMContentLoaded', () => {
resolve(document)
})
}
})
}
document.ready().then(...)
document.ready = function () {
return new Promise(function (resolve) {
if (document.readyState === "complete") {
resolve()
} else {
document.addEventListener("DOMContentLoaded", resolve)
}
})
}
document.ready().then(someFunction)
See also tips listed here.