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

 


 

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' }
}
*/

 


 

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

Sourced from here:

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
}

 


 

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(...)

or as listed here

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.