A collection of snippets that might come in handy, inspired by 30 seconds of code and similar projects
Converts a comma-separated values (CSV) string to a 2D array.
- Use
Array.prototype.slice()
andArray.prototype.indexOf('\n')
to remove the first row (title row) ifomitFirstRow
istrue
. - Use
String.prototype.split('\n')
to create a string for each row, thenString.prototype.split(delimiter)
to separate the values in each row. - Omit the second argument,
delimiter
, to use a default delimiter of','
. - Omit the third argument,
omitFirstRow
, to include the first row (title row) of the CSV string.
const CSVToArray = (data, delimiter = ",", omitFirstRow = false) =>
data
.slice(omitFirstRow ? data.indexOf("\n") + 1 : 0)
.split("\n")
.map((v) => v.split(delimiter));
CSVToArray("a,b\nc,d"); // [['a', 'b'], ['c', 'd']];
CSVToArray("a;b\nc;d", ";"); // [['a', 'b'], ['c', 'd']];
CSVToArray("col1,col2\na,b\nc,d", ",", true); // [['a', 'b'], ['c', 'd']];
Converts a comma-separated values (CSV) string to a 2D array of objects. The first row of the string is used as the title row.
- Use
Array.prototype.slice()
andArray.prototype.indexOf('\n')
andString.prototype.split(delimiter)
to separate the first row (title row) into values. - Use
String.prototype.split('\n')
to create a string for each row, thenArray.prototype.map()
andString.prototype.split(delimiter)
to separate the values in each row. - Use
Array.prototype.reduce()
to create an object for each row's values, with the keys parsed from the title row. - Omit the second argument,
delimiter
, to use a default delimiter of,
.
const CSVToJSON = (data, delimiter = ",") => {
const titles = data.slice(0, data.indexOf("\n")).split(delimiter);
return data
.slice(data.indexOf("\n") + 1)
.split("\n")
.map((v) => {
const values = v.split(delimiter);
return titles.reduce(
(obj, title, index) => ((obj[title] = values[index]), obj),
{}
);
});
};
CSVToJSON("col1,col2\na,b\nc,d");
// [{'col1': 'a', 'col2': 'b'}, {'col1': 'c', 'col2': 'd'}];
CSVToJSON("col1;col2\na;b\nc;d", ";");
// [{'col1': 'a', 'col2': 'b'}, {'col1': 'c', 'col2': 'd'}];
Converts a comma-separated values (CSV) string to a 2D array.
- Use
Array.prototype.slice()
andArray.prototype.indexOf('\n')
to remove the first row (title row) ifomitFirstRow
istrue
. - Use
String.prototype.split('\n')
to create a string for each row, thenString.prototype.split(delimiter)
to separate the values in each row. - Omit the second argument,
delimiter
, to use a default delimiter of','
. - Omit the third argument,
omitFirstRow
, to include the first row (title row) of the CSV string.
const CSVToArray = (data, delimiter = ",", omitFirstRow = false) =>
data
.slice(omitFirstRow ? data.indexOf("\n") + 1 : 0)
.split("\n")
.map((v) => v.split(delimiter));
CSVToArray("a,b\nc,d"); // [['a', 'b'], ['c', 'd']];
CSVToArray("a;b\nc;d", ";"); // [['a', 'b'], ['c', 'd']];
CSVToArray("col1,col2\na,b\nc,d", ",", true); // [['a', 'b'], ['c', 'd']];
Converts a comma-separated values (CSV) string to a 2D array of objects. The first row of the string is used as the title row.
- Use
Array.prototype.slice()
andArray.prototype.indexOf('\n')
andString.prototype.split(delimiter)
to separate the first row (title row) into values. - Use
String.prototype.split('\n')
to create a string for each row, thenArray.prototype.map()
andString.prototype.split(delimiter)
to separate the values in each row. - Use
Array.prototype.reduce()
to create an object for each row's values, with the keys parsed from the title row. - Omit the second argument,
delimiter
, to use a default delimiter of,
.
const CSVToJSON = (data, delimiter = ",") => {
const titles = data.slice(0, data.indexOf("\n")).split(delimiter);
return data
.slice(data.indexOf("\n") + 1)
.split("\n")
.map((v) => {
const values = v.split(delimiter);
return titles.reduce(
(obj, title, index) => ((obj[title] = values[index]), obj),
{}
);
});
};
CSVToJSON("col1,col2\na,b\nc,d");
// [{'col1': 'a', 'col2': 'b'}, {'col1': 'c', 'col2': 'd'}];
CSVToJSON("col1;col2\na;b\nc;d", ";");
// [{'col1': 'a', 'col2': 'b'}, {'col1': 'c', 'col2': 'd'}];
Converts a HSB color tuple to RGB format.
- Use the HSB to RGB conversion formula to convert to the appropriate format.
- The range of the input parameters is H: [0, 360], S: [0, 100], B: [0, 100].
- The range of all output values is [0, 255].
const HSBToRGB = (h, s, b) => {
s /= 100;
b /= 100;
const k = (n) => (n + h / 60) % 6;
const f = (n) => b * (1 - s * Math.max(0, Math.min(k(n), 4 - k(n), 1)));
return [255 * f(5), 255 * f(3), 255 * f(1)];
};
HSBToRGB(18, 81, 99); // [252.45, 109.31084999999996, 47.965499999999984]
Converts a HSL color tuple to RGB format.
- Use the HSL to RGB conversion formula to convert to the appropriate format.
- The range of the input parameters is H: [0, 360], S: [0, 100], L: [0, 100].
- The range of all output values is [0, 255].
const HSLToRGB = (h, s, l) => {
s /= 100;
l /= 100;
const k = (n) => (n + h / 30) % 12;
const a = s * Math.min(l, 1 - l);
const f = (n) =>
l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));
return [255 * f(0), 255 * f(8), 255 * f(4)];
};
HSLToRGB(13, 100, 11); // [56.1, 12.155, 0]
Writes a JSON object to a file.
- Use
fs.writeFileSync()
, template literals andJSON.stringify()
to write ajson
object to a.json
file.
const fs = require("fs");
const JSONToFile = (obj, filename) =>
fs.writeFileSync(`${filename}.json`, JSON.stringify(obj, null, 2));
JSONToFile({ test: "is passed" }, "testJsonFile");
// writes the object to 'testJsonFile.json'
Converts an array of objects to a comma-separated values (CSV) string that contains only the columns
specified.
- Use
Array.prototype.join(delimiter)
to combine all the names incolumns
to create the first row. - Use
Array.prototype.map()
andArray.prototype.reduce()
to create a row for each object. Substitute non-existent values with empty strings and only mapping values incolumns
. - Use
Array.prototype.join('\n')
to combine all rows into a string. - Omit the third argument,
delimiter
, to use a default delimiter of','
.
const JSONtoCSV = (arr, columns, delimiter = ",") =>
[
columns.join(delimiter),
...arr.map((obj) =>
columns.reduce(
(acc, key) =>
`${acc}${!acc.length ? "" : delimiter}"${!obj[key] ? "" : obj[key]}"`,
""
)
),
].join("\n");
JSONtoCSV(
[{ a: 1, b: 2 }, { a: 3, b: 4, c: 5 }, { a: 6 }, { b: 7 }],
["a", "b"]
); // 'a,b\n"1","2"\n"3","4"\n"6",""\n"","7"'
JSONtoCSV(
[{ a: 1, b: 2 }, { a: 3, b: 4, c: 5 }, { a: 6 }, { b: 7 }],
["a", "b"],
";"
); // 'a;b\n"1";"2"\n"3";"4"\n"6";""\n"";"7"'
Converts a RGB color tuple to HSB format.
- Use the RGB to HSB conversion formula to convert to the appropriate format.
- The range of all input parameters is [0, 255].
- The range of the resulting values is H: [0, 360], S: [0, 100], B: [0, 100].
const RGBToHSB = (r, g, b) => {
r /= 255;
g /= 255;
b /= 255;
const v = Math.max(r, g, b),
n = v - Math.min(r, g, b);
const h =
n === 0
? 0
: n && v === r
? (g - b) / n
: v === g
? 2 + (b - r) / n
: 4 + (r - g) / n;
return [60 * (h < 0 ? h + 6 : h), v && (n / v) * 100, v * 100];
};
RGBToHSB(252, 111, 48);
// [18.529411764705856, 80.95238095238095, 98.82352941176471]
Converts a RGB color tuple to HSL format.
- Use the RGB to HSL conversion formula to convert to the appropriate format.
- The range of all input parameters is [0, 255].
- The range of the resulting values is H: [0, 360], S: [0, 100], L: [0, 100].
const RGBToHSL = (r, g, b) => {
r /= 255;
g /= 255;
b /= 255;
const l = Math.max(r, g, b);
const s = l - Math.min(r, g, b);
const h = s
? l === r
? (g - b) / s
: l === g
? 2 + (b - r) / s
: 4 + (r - g) / s
: 0;
return [
60 * h < 0 ? 60 * h + 360 : 60 * h,
100 * (s ? (l <= 0.5 ? s / (2 * l - s) : s / (2 - (2 * l - s))) : 0),
(100 * (2 * l - s)) / 2,
];
};
RGBToHSL(45, 23, 11); // [21.17647, 60.71428, 10.98039]
Converts the values of RGB components to a hexadecimal color code.
- Convert given RGB parameters to hexadecimal string using bitwise left-shift operator (
<<
) andNumber.prototype.toString(16)
. - Use
String.prototype.padStart(6, '0')
to get a 6-digit hexadecimal value.
const RGBToHex = (r, g, b) =>
((r << 16) + (g << 8) + b).toString(16).padStart(6, "0");
RGBToHex(255, 165, 1); // 'ffa501'
Joins all given URL segments together, then normalizes the resulting URL.
- Use
String.prototype.join('/')
to combine URL segments. - Use a series of
String.prototype.replace()
calls with various regexps to normalize the resulting URL (remove double slashes, add proper slashes for protocol, remove slashes before parameters, combine parameters with'&'
and normalize first parameter delimiter).
const URLJoin = (...args) =>
args
.join("/")
.replace(/[\/]+/g, "/")
.replace(/^(.+):\//, "$1://")
.replace(/^file:/, "file:/")
.replace(/\/(\?|&|#[^!])/g, "$1")
.replace(/\?/g, "&")
.replace("&", "?");
URLJoin("http://www.google.com", "a", "/b/cd", "?foo=123", "?bar=foo");
// 'http://www.google.com/a/b/cd?foo=123&bar=foo'
Generates a UUID in a browser.
- Use
Crypto.getRandomValues()
to generate a UUID, compliant with RFC4122 version 4. - Use
Number.prototype.toString(16)
to convert it to a proper UUID.
const UUIDGeneratorBrowser = () =>
([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) =>
(
c ^
(crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))
).toString(16)
);
UUIDGeneratorBrowser(); // '7982fcfe-5721-4632-bede-6000885be57d'
Generates a UUID in Node.JS.
- Use
crypto.randomBytes()
to generate a UUID, compliant with RFC4122 version 4. - Use
Number.prototype.toString(16)
to convert it to a proper UUID.
const crypto = require("crypto");
const UUIDGeneratorNode = () =>
([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) =>
(c ^ (crypto.randomBytes(1)[0] & (15 >> (c / 4)))).toString(16)
);
UUIDGeneratorNode(); // '79c7c136-60ee-40a2-beb2-856f1feabefc'
Creates an array of partial sums.
- Use
Array.prototype.reduce()
, initialized with an empty array accumulator to iterate overnums
. - Use
Array.prototype.slice(-1)
, the spread operator (...
) and the unary+
operator to add each value to the accumulator array containing the previous sums.
const accumulate = (...nums) =>
nums.reduce((acc, n) => [...acc, n + +acc.slice(-1)], []);
accumulate(1, 2, 3, 4); // [1, 3, 6, 10]
accumulate(...[1, 2, 3, 4]); // [1, 3, 6, 10]
Adds a class to an HTML element.
- Use
Element.classList
andDOMTokenList.add()
to add the specified class to the element.
const addClass = (el, className) => el.classList.add(className);
addClass(document.querySelector("p"), "special");
// The paragraph will now have the 'special' class
Calculates the date of n
days from the given date, returning its string representation.
- Use
new Date()
to create a date object from the first argument. - Use
Date.prototype.getDate()
andDate.prototype.setDate()
to addn
days to the given date. - Use
Date.prototype.toISOString()
to return a string inyyyy-mm-dd
format.
const addDaysToDate = (date, n) => {
const d = new Date(date);
d.setDate(d.getDate() + n);
return d.toISOString().split("T")[0];
};
addDaysToDate("2020-10-15", 10); // '2020-10-25'
addDaysToDate("2020-10-15", -10); // '2020-10-05'
Attaches an event listener to all the provided targets.
- Use
Array.prototype.forEach()
andEventTarget.addEventListener()
to attach the providedlistener
for the given eventtype
to alltargets
.
const addEventListenerAll = (targets, type, listener, options, useCapture) => {
targets.forEach((target) =>
target.addEventListener(type, listener, options, useCapture)
);
};
addEventListenerAll(document.querySelectorAll("a"), "click", () =>
console.log("Clicked a link")
);
// Logs 'Clicked a link' whenever any anchor element is clicked
Calculates the date of n
minutes from the given date, returning its string representation.
- Use
new Date()
to create a date object from the first argument. - Use
Date.prototype.getTime()
andDate.prototype.setTime()
to addn
minutes to the given date. - Use
Date.prototype.toISOString()
,String.prototype.split()
andString.prototype.replace()
to return a string inyyyy-mm-dd HH:MM:SS
format.
const addMinutesToDate = (date, n) => {
const d = new Date(date);
d.setTime(d.getTime() + n * 60000);
return d.toISOString().split(".")[0].replace("T", " ");
};
addMinutesToDate("2020-10-19 12:00:00", 10); // '2020-10-19 12:10:00'
addMinutesToDate("2020-10-19", -10); // '2020-10-18 23:50:00'
Adds multiple event listeners with the same handler to an element.
- Use
Array.prototype.forEach()
andEventTarget.addEventListener()
to add multiple event listeners with an assigned callback function to an element.
const addMultipleListeners = (el, types, listener, options, useCapture) => {
types.forEach((type) =>
el.addEventListener(type, listener, options, useCapture)
);
};
addMultipleListeners(
document.querySelector(".my-element"),
["click", "mousedown"],
() => {
console.log("hello!");
}
);
Adds the provided styles to the given element.
- Use
Object.assign()
andElementCSSInlineStyle.style
to merge the providedstyles
object into the style of the given element.
const addStyles = (el, styles) => Object.assign(el.style, styles);
addStyles(document.getElementById("my-element"), {
background: "red",
color: "#ffff00",
fontSize: "3rem",
});
Calculates the date after adding the given number of business days.
- Use
Array.from()
to construct an array withlength
equal to thecount
of business days to be added. - Use
Array.prototype.reduce()
to iterate over the array, starting fromstartDate
and incrementing, usingDate.prototype.getDate()
andDate.prototype.setDate()
. - If the current
date
is on a weekend, update it again by adding either one day or two days to make it a weekday. - NOTE: Does not take official holidays into account.
const addWeekDays = (startDate, count) =>
Array.from({ length: count }).reduce((date) => {
date = new Date(date.setDate(date.getDate() + 1));
if (date.getDay() % 6 === 0)
date = new Date(date.setDate(date.getDate() + (date.getDay() / 6 + 1)));
return date;
}, startDate);
addWeekDays(new Date("Oct 09, 2020"), 5); // 'Oct 16, 2020'
addWeekDays(new Date("Oct 12, 2020"), 5); // 'Oct 19, 2020'
Checks if the provided predicate function returns true
for all elements in a collection.
- Use
Array.prototype.every()
to test if all elements in the collection returntrue
based onfn
. - Omit the second argument,
fn
, to useBoolean
as a default.
const all = (arr, fn = Boolean) => arr.every(fn);
all([4, 2, 3], (x) => x > 1); // true
all([1, 2, 3]); // true
Checks if all elements in an array are equal.
- Use
Array.prototype.every()
to check if all the elements of the array are the same as the first one. - Elements in the array are compared using the strict comparison operator, which does not account for
NaN
self-inequality.
const allEqual = (arr) => arr.every((val) => val === arr[0]);
allEqual([1, 2, 3, 4, 5, 6]); // false
allEqual([1, 1, 1, 1]); // true
Checks if all elements in an array are equal, based on the provided mapping function.
- Apply
fn
to the first element ofarr
. - Use
Array.prototype.every()
to check iffn
returns the same value for all elements in the array as it did for the first one. - Elements in the array are compared using the strict comparison operator, which does not account for
NaN
self-inequality.
const allEqualBy = (arr, fn) => {
const eql = fn(arr[0]);
return arr.every((val) => fn(val) === eql);
};
allEqualBy([1.1, 1.2, 1.3], Math.round); // true
allEqualBy([1.1, 1.3, 1.6], Math.round); // false
Checks if all elements in an array are unique.
- Create a new
Set
from the mapped values to keep only unique occurrences. - Use
Array.prototype.length
andSet.prototype.size
to compare the length of the unique values to the original array.
const allUnique = (arr) => arr.length === new Set(arr).size;
allUnique([1, 2, 3, 4]); // true
allUnique([1, 1, 2, 3]); // false
Checks if all elements in an array are unique, based on the provided mapping function.
- Use
Array.prototype.map()
to applyfn
to all elements inarr
. - Create a new
Set
from the mapped values to keep only unique occurrences. - Use
Array.prototype.length
andSet.prototype.size
to compare the length of the unique mapped values to the original array.
const allUniqueBy = (arr, fn) => arr.length === new Set(arr.map(fn)).size;
allUniqueBy([1.2, 2.4, 2.9], Math.round); // true
allUniqueBy([1.2, 2.3, 2.4], Math.round); // false
title: and unlisted: true
Checks if both arguments are true
.
- Use the logical and (
&&
) operator on the two given values.
const and = (a, b) => a && b;
and(true, true); // true
and(true, false); // false
and(false, false); // false
Checks if the provided predicate function returns true
for at least one element in a collection.
- Use
Array.prototype.some()
to test if any elements in the collection returntrue
based onfn
. - Omit the second argument,
fn
, to useBoolean
as a default.
const any = (arr, fn = Boolean) => arr.some(fn);
any([0, 1, 2, 0], (x) => x >= 2); // true
any([0, 0, 1, 0]); // true
Creates an array of n
-tuples of consecutive elements.
- Use
Array.prototype.slice()
andArray.prototype.map()
to create an array of appropriate length. - Populate the array with
n
-tuples of consecutive elements fromarr
. - If
n
is greater than the length ofarr
, return an empty array.
const aperture = (n, arr) =>
n > arr.length ? [] : arr.slice(n - 1).map((v, i) => arr.slice(i, i + n));
aperture(2, [1, 2, 3, 4]); // [[1, 2], [2, 3], [3, 4]]
aperture(3, [1, 2, 3, 4]); // [[1, 2, 3], [2, 3, 4]]
aperture(5, [1, 2, 3, 4]); // []
Checks if two numbers are approximately equal to each other.
- Use
Math.abs()
to compare the absolute difference of the two values toepsilon
. - Omit the third argument,
epsilon
, to use a default value of0.001
.
const approximatelyEqual = (v1, v2, epsilon = 0.001) =>
Math.abs(v1 - v2) < epsilon;
approximatelyEqual(Math.PI / 2.0, 1.5708); // true
Creates an array of numbers in the arithmetic progression, starting with the given positive integer and up to the specified limit.
- Use
Array.from()
to create an array of the desired length,lim/n
. Use a map function to fill it with the desired values in the given range.
const arithmeticProgression = (n, lim) =>
Array.from({ length: Math.ceil(lim / n) }, (_, i) => (i + 1) * n);
arithmeticProgression(5, 25); // [5, 10, 15, 20, 25]
Converts a 2D array to a comma-separated values (CSV) string.
- Use
Array.prototype.map()
andArray.prototype.join(delimiter)
to combine individual 1D arrays (rows) into strings. - Use
Array.prototype.join('\n')
to combine all rows into a CSV string, separating each row with a newline. - Omit the second argument,
delimiter
, to use a default delimiter of,
.
const arrayToCSV = (arr, delimiter = ",") =>
arr
.map((v) =>
v
.map((x) => (isNaN(x) ? `"${x.replace(/"/g, '""')}"` : x))
.join(delimiter)
)
.join("\n");
arrayToCSV([
["a", "b"],
["c", "d"],
]); // '"a","b"\n"c","d"'
arrayToCSV(
[
["a", "b"],
["c", "d"],
],
";"
); // '"a";"b"\n"c";"d"'
arrayToCSV([
["a", '"b" great'],
["c", 3.1415],
]);
// '"a","""b"" great"\n"c",3.1415'
Converts the given array elements into <li>
tags and appends them to the list of the given id.
- Use
Array.prototype.map()
andDocument.querySelector()
to create a list of html tags.
const arrayToHTMLList = (arr, listID) =>
(document.querySelector(`#${listID}`).innerHTML += arr
.map((item) => `<li>${item}</li>`)
.join(""));
arrayToHTMLList(["item 1", "item 2"], "myListID");
Creates a function that accepts up to n
arguments, ignoring any additional arguments.
- Call the provided function,
fn
, with up ton
arguments, usingArray.prototype.slice(0, n)
and the spread operator (...
).
const ary =
(fn, n) =>
(...args) =>
fn(...args.slice(0, n));
const firstTwoMax = ary(Math.max, 2);
[[2, 6, "a"], [6, 4, 8], [10]].map((x) => firstTwoMax(...x)); // [6, 6, 10]
Validates all keys in an object match the given keys
.
- Use
Object.keys()
to get the keys of the given object,obj
. - Use
Array.prototype.every()
andArray.prototype.includes()
to validate that each key in the object is specified in thekeys
array.
const assertValidKeys = (obj, keys) =>
Object.keys(obj).every((key) => keys.includes(key));
assertValidKeys({ id: 10, name: "apple" }, ["id", "name"]); // true
assertValidKeys({ id: 10, name: "apple" }, ["id", "type"]); // false
Decodes a string of data which has been encoded using base-64 encoding.
- Create a
Buffer
for the given string with base-64 encoding and useBuffer.toString('binary')
to return the decoded string.
const atob = (str) => Buffer.from(str, "base64").toString("binary");
atob("Zm9vYmFy"); // 'foobar'
Attempts to invoke a function with the provided arguments, returning either the result or the caught error object.
- Use a
try... catch
block to return either the result of the function or an appropriate error. - If the caught object is not an
Error
, use it to create a newError
.
const attempt = (fn, ...args) => {
try {
return fn(...args);
} catch (e) {
return e instanceof Error ? e : new Error(e);
}
};
let elements = attempt(function (selector) {
return document.querySelectorAll(selector);
}, ">_>");
if (elements instanceof Error) elements = []; // elements = []
Calculates the average of two or more numbers.
- Use
Array.prototype.reduce()
to add each value to an accumulator, initialized with a value of0
. - Divide the resulting array by its length.
const average = (...nums) =>
nums.reduce((acc, val) => acc + val, 0) / nums.length;
average(...[1, 2, 3]); // 2
average(1, 2, 3); // 2
Calculates the average of an array, after mapping each element to a value using the provided function.
- Use
Array.prototype.map()
to map each element to the value returned byfn
. - Use
Array.prototype.reduce()
to add each value to an accumulator, initialized with a value of0
. - Divide the resulting array by its length.
const averageBy = (arr, fn) =>
arr
.map(typeof fn === "function" ? fn : (val) => val[fn])
.reduce((acc, val) => acc + val, 0) / arr.length;
averageBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], (o) => o.n); // 5
averageBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], "n"); // 5
Splits values into two groups, based on the result of the given filter
array.
- Use
Array.prototype.reduce()
andArray.prototype.push()
to add elements to groups, based onfilter
. - If
filter
has a truthy value for any element, add it to the first group, otherwise add it to the second group.
const bifurcate = (arr, filter) =>
arr.reduce(
(acc, val, i) => (acc[filter[i] ? 0 : 1].push(val), acc),
[[], []]
);
bifurcate(["beep", "boop", "foo", "bar"], [true, true, false, true]);
// [ ['beep', 'boop', 'bar'], ['foo'] ]
Splits values into two groups, based on the result of the given filtering function.
- Use
Array.prototype.reduce()
andArray.prototype.push()
to add elements to groups, based on the value returned byfn
for each element. - If
fn
returns a truthy value for any element, add it to the first group, otherwise add it to the second group.
const bifurcateBy = (arr, fn) =>
arr.reduce(
(acc, val, i) => (acc[fn(val, i) ? 0 : 1].push(val), acc),
[[], []]
);
bifurcateBy(["beep", "boop", "foo", "bar"], (x) => x[0] === "b");
// [ ['beep', 'boop', 'bar'], ['foo'] ]
Creates a function that accepts up to two arguments, ignoring any additional arguments.
- Call the provided function,
fn
, with the first two arguments given.
const binary = (fn) => (a, b) => fn(a, b);
["2", "1", "0"].map(binary(Math.max)); // [2, 1, 2]
Finds the index of a given element in a sorted array using the binary search algorithm.
- Declare the left and right search boundaries,
l
andr
, initialized to0
and thelength
of the array respectively. - Use a
while
loop to repeatedly narrow down the search subarray, usingMath.floor()
to cut it in half. - Return the index of the element if found, otherwise return
-1
. - Note: Does not account for duplicate values in the array.
const binarySearch = (arr, item) => {
let l = 0,
r = arr.length - 1;
while (l <= r) {
const mid = Math.floor((l + r) / 2);
const guess = arr[mid];
if (guess === item) return mid;
if (guess > item) r = mid - 1;
else l = mid + 1;
}
return -1;
};
binarySearch([1, 2, 3, 4, 5], 1); // 0
binarySearch([1, 2, 3, 4, 5], 5); // 4
binarySearch([1, 2, 3, 4, 5], 6); // -1
Creates a function that invokes fn
with a given context, optionally prepending any additional supplied parameters to the arguments.
- Return a
function
that usesFunction.prototype.apply()
to apply the givencontext
tofn
. - Use the spread operator (
...
) to prepend any additional supplied parameters to the arguments.
const bind =
(fn, context, ...boundArgs) =>
(...args) =>
fn.apply(context, [...boundArgs, ...args]);
function greet(greeting, punctuation) {
return greeting + " " + this.user + punctuation;
}
const freddy = { user: "fred" };
const freddyBound = bind(greet, freddy);
console.log(freddyBound("hi", "!")); // 'hi fred!'
Binds methods of an object to the object itself, overwriting the existing method.
- Use
Array.prototype.forEach()
to iterate over the givenfns
. - Return a function for each one, using
Function.prototype.apply()
to apply the given context (obj
) tofn
.
const bindAll = (obj, ...fns) =>
fns.forEach(
(fn) => (
(f = obj[fn]),
(obj[fn] = function () {
return f.apply(obj);
})
)
);
let view = {
label: "docs",
click: function () {
console.log("clicked " + this.label);
},
};
bindAll(view, "click");
document.body.addEventListener("click", view.click);
// Log 'clicked docs' when clicked.
Creates a function that invokes the method at a given key of an object, optionally prepending any additional supplied parameters to the arguments.
- Return a
function
that usesFunction.prototype.apply()
to bindcontext[fn]
tocontext
. - Use the spread operator (
...
) to prepend any additional supplied parameters to the arguments.
const bindKey =
(context, fn, ...boundArgs) =>
(...args) =>
context[fn].apply(context, [...boundArgs, ...args]);
const freddy = {
user: "fred",
greet: function (greeting, punctuation) {
return greeting + " " + this.user + punctuation;
},
};
const freddyBound = bindKey(freddy, "greet");
console.log(freddyBound("hi", "!")); // 'hi fred!'
Calculates the number of ways to choose k
items from n
items without repetition and without order.
- Use
Number.isNaN()
to check if any of the two values isNaN
. - Check if
k
is less than0
, greater than or equal ton
, equal to1
orn - 1
and return the appropriate result. - Check if
n - k
is less thank
and switch their values accordingly. - Loop from
2
throughk
and calculate the binomial coefficient. - Use
Math.round()
to account for rounding errors in the calculation.
const binomialCoefficient = (n, k) => {
if (Number.isNaN(n) || Number.isNaN(k)) return NaN;
if (k < 0 || k > n) return 0;
if (k === 0 || k === n) return 1;
if (k === 1 || k === n - 1) return n;
if (n - k < k) k = n - k;
let res = n;
for (let j = 2; j <= k; j++) res *= (n - j + 1) / j;
return Math.round(res);
};
binomialCoefficient(8, 2); // 28
title: both unlisted: true
Checks if both of the given functions return true
for a given set of arguments.
- Use the logical and (
&&
) operator on the result of calling the two functions with the suppliedargs
.
const both =
(f, g) =>
(...args) =>
f(...args) && g(...args);
const isEven = (num) => num % 2 === 0;
const isPositive = (num) => num > 0;
const isPositiveEven = both(isEven, isPositive);
isPositiveEven(4); // true
isPositiveEven(-2); // false
Converts a HSB color tuple to RGB format.
- Use the HSB to RGB conversion formula to convert to the appropriate format.
- The range of the input parameters is H: [0, 360], S: [0, 100], B: [0, 100].
- The range of all output values is [0, 255].
const HSBToRGB = (h, s, b) => {
s /= 100;
b /= 100;
const k = (n) => (n + h / 60) % 6;
const f = (n) => b * (1 - s * Math.max(0, Math.min(k(n), 4 - k(n), 1)));
return [255 * f(5), 255 * f(3), 255 * f(1)];
};
HSBToRGB(18, 81, 99); // [252.45, 109.31084999999996, 47.965499999999984]
Converts a HSL color tuple to RGB format.
- Use the HSL to RGB conversion formula to convert to the appropriate format.
- The range of the input parameters is H: [0, 360], S: [0, 100], L: [0, 100].
- The range of all output values is [0, 255].
const HSLToRGB = (h, s, l) => {
s /= 100;
l /= 100;
const k = (n) => (n + h / 30) % 12;
const a = s * Math.min(l, 1 - l);
const f = (n) =>
l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));
return [255 * f(0), 255 * f(8), 255 * f(4)];
};
HSLToRGB(13, 100, 11); // [56.1, 12.155, 0]
Writes a JSON object to a file.
- Use
fs.writeFileSync()
, template literals andJSON.stringify()
to write ajson
object to a.json
file.
const fs = require("fs");
const JSONToFile = (obj, filename) =>
fs.writeFileSync(`${filename}.json`, JSON.stringify(obj, null, 2));
JSONToFile({ test: "is passed" }, "testJsonFile");
// writes the object to 'testJsonFile.json'
Converts an array of objects to a comma-separated values (CSV) string that contains only the columns
specified.
- Use
Array.prototype.join(delimiter)
to combine all the names incolumns
to create the first row. - Use
Array.prototype.map()
andArray.prototype.reduce()
to create a row for each object. Substitute non-existent values with empty strings and only mapping values incolumns
. - Use
Array.prototype.join('\n')
to combine all rows into a string. - Omit the third argument,
delimiter
, to use a default delimiter of','
.
const JSONtoCSV = (arr, columns, delimiter = ",") =>
[
columns.join(delimiter),
...arr.map((obj) =>
columns.reduce(
(acc, key) =>
`${acc}${!acc.length ? "" : delimiter}"${!obj[key] ? "" : obj[key]}"`,
""
)
),
].join("\n");
JSONtoCSV(
[{ a: 1, b: 2 }, { a: 3, b: 4, c: 5 }, { a: 6 }, { b: 7 }],
["a", "b"]
); // 'a,b\n"1","2"\n"3","4"\n"6",""\n"","7"'
JSONtoCSV(
[{ a: 1, b: 2 }, { a: 3, b: 4, c: 5 }, { a: 6 }, { b: 7 }],
["a", "b"],
";"
); // 'a;b\n"1";"2"\n"3";"4"\n"6";""\n"";"7"'
Converts a RGB color tuple to HSB format.
- Use the RGB to HSB conversion formula to convert to the appropriate format.
- The range of all input parameters is [0, 255].
- The range of the resulting values is H: [0, 360], S: [0, 100], B: [0, 100].
const RGBToHSB = (r, g, b) => {
r /= 255;
g /= 255;
b /= 255;
const v = Math.max(r, g, b),
n = v - Math.min(r, g, b);
const h =
n === 0
? 0
: n && v === r
? (g - b) / n
: v === g
? 2 + (b - r) / n
: 4 + (r - g) / n;
return [60 * (h < 0 ? h + 6 : h), v && (n / v) * 100, v * 100];
};
RGBToHSB(252, 111, 48);
// [18.529411764705856, 80.95238095238095, 98.82352941176471]
Converts a RGB color tuple to HSL format.
- Use the RGB to HSL conversion formula to convert to the appropriate format.
- The range of all input parameters is [0, 255].
- The range of the resulting values is H: [0, 360], S: [0, 100], L: [0, 100].
const RGBToHSL = (r, g, b) => {
r /= 255;
g /= 255;
b /= 255;
const l = Math.max(r, g, b);
const s = l - Math.min(r, g, b);
const h = s
? l === r
? (g - b) / s
: l === g
? 2 + (b - r) / s
: 4 + (r - g) / s
: 0;
return [
60 * h < 0 ? 60 * h + 360 : 60 * h,
100 * (s ? (l <= 0.5 ? s / (2 * l - s) : s / (2 - (2 * l - s))) : 0),
(100 * (2 * l - s)) / 2,
];
};
RGBToHSL(45, 23, 11); // [21.17647, 60.71428, 10.98039]
Converts the values of RGB components to a hexadecimal color code.
- Convert given RGB parameters to hexadecimal string using bitwise left-shift operator (
<<
) andNumber.prototype.toString(16)
. - Use
String.prototype.padStart(6, '0')
to get a 6-digit hexadecimal value.
const RGBToHex = (r, g, b) =>
((r << 16) + (g << 8) + b).toString(16).padStart(6, "0");
RGBToHex(255, 165, 1); // 'ffa501'
Joins all given URL segments together, then normalizes the resulting URL.
- Use
String.prototype.join('/')
to combine URL segments. - Use a series of
String.prototype.replace()
calls with various regexps to normalize the resulting URL (remove double slashes, add proper slashes for protocol, remove slashes before parameters, combine parameters with'&'
and normalize first parameter delimiter).
const URLJoin = (...args) =>
args
.join("/")
.replace(/[\/]+/g, "/")
.replace(/^(.+):\//, "$1://")
.replace(/^file:/, "file:/")
.replace(/\/(\?|&|#[^!])/g, "$1")
.replace(/\?/g, "&")
.replace("&", "?");
URLJoin("http://www.google.com", "a", "/b/cd", "?foo=123", "?bar=foo");
// 'http://www.google.com/a/b/cd?foo=123&bar=foo'
Generates a UUID in a browser.
- Use
Crypto.getRandomValues()
to generate a UUID, compliant with RFC4122 version 4. - Use
Number.prototype.toString(16)
to convert it to a proper UUID.
const UUIDGeneratorBrowser = () =>
([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) =>
(
c ^
(crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))
).toString(16)
);
UUIDGeneratorBrowser(); // '7982fcfe-5721-4632-bede-6000885be57d'
Generates a UUID in Node.JS.
- Use
crypto.randomBytes()
to generate a UUID, compliant with RFC4122 version 4. - Use
Number.prototype.toString(16)
to convert it to a proper UUID.
const crypto = require("crypto");
const UUIDGeneratorNode = () =>
([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) =>
(c ^ (crypto.randomBytes(1)[0] & (15 >> (c / 4)))).toString(16)
);
UUIDGeneratorNode(); // '79c7c136-60ee-40a2-beb2-856f1feabefc'
Creates an array of partial sums.
- Use
Array.prototype.reduce()
, initialized with an empty array accumulator to iterate overnums
. - Use
Array.prototype.slice(-1)
, the spread operator (...
) and the unary+
operator to add each value to the accumulator array containing the previous sums.
const accumulate = (...nums) =>
nums.reduce((acc, n) => [...acc, n + +acc.slice(-1)], []);
accumulate(1, 2, 3, 4); // [1, 3, 6, 10]
accumulate(...[1, 2, 3, 4]); // [1, 3, 6, 10]
Adds a class to an HTML element.
- Use
Element.classList
andDOMTokenList.add()
to add the specified class to the element.
const addClass = (el, className) => el.classList.add(className);
addClass(document.querySelector("p"), "special");
// The paragraph will now have the 'special' class
Calculates the date of n
days from the given date, returning its string representation.
- Use
new Date()
to create a date object from the first argument. - Use
Date.prototype.getDate()
andDate.prototype.setDate()
to addn
days to the given date. - Use
Date.prototype.toISOString()
to return a string inyyyy-mm-dd
format.
const addDaysToDate = (date, n) => {
const d = new Date(date);
d.setDate(d.getDate() + n);
return d.toISOString().split("T")[0];
};
addDaysToDate("2020-10-15", 10); // '2020-10-25'
addDaysToDate("2020-10-15", -10); // '2020-10-05'
Attaches an event listener to all the provided targets.
- Use
Array.prototype.forEach()
andEventTarget.addEventListener()
to attach the providedlistener
for the given eventtype
to alltargets
.
const addEventListenerAll = (targets, type, listener, options, useCapture) => {
targets.forEach((target) =>
target.addEventListener(type, listener, options, useCapture)
);
};
addEventListenerAll(document.querySelectorAll("a"), "click", () =>
console.log("Clicked a link")
);
// Logs 'Clicked a link' whenever any anchor element is clicked
Calculates the date of n
minutes from the given date, returning its string representation.
- Use
new Date()
to create a date object from the first argument. - Use
Date.prototype.getTime()
andDate.prototype.setTime()
to addn
minutes to the given date. - Use
Date.prototype.toISOString()
,String.prototype.split()
andString.prototype.replace()
to return a string inyyyy-mm-dd HH:MM:SS
format.
const addMinutesToDate = (date, n) => {
const d = new Date(date);
d.setTime(d.getTime() + n * 60000);
return d.toISOString().split(".")[0].replace("T", " ");
};
addMinutesToDate("2020-10-19 12:00:00", 10); // '2020-10-19 12:10:00'
addMinutesToDate("2020-10-19", -10); // '2020-10-18 23:50:00'
Adds multiple event listeners with the same handler to an element.
- Use
Array.prototype.forEach()
andEventTarget.addEventListener()
to add multiple event listeners with an assigned callback function to an element.
const addMultipleListeners = (el, types, listener, options, useCapture) => {
types.forEach((type) =>
el.addEventListener(type, listener, options, useCapture)
);
};
addMultipleListeners(
document.querySelector(".my-element"),
["click", "mousedown"],
() => {
console.log("hello!");
}
);
Adds the provided styles to the given element.
- Use
Object.assign()
andElementCSSInlineStyle.style
to merge the providedstyles
object into the style of the given element.
const addStyles = (el, styles) => Object.assign(el.style, styles);
addStyles(document.getElementById("my-element"), {
background: "red",
color: "#ffff00",
fontSize: "3rem",
});
Calculates the date after adding the given number of business days.
- Use
Array.from()
to construct an array withlength
equal to thecount
of business days to be added. - Use
Array.prototype.reduce()
to iterate over the array, starting fromstartDate
and incrementing, usingDate.prototype.getDate()
andDate.prototype.setDate()
. - If the current
date
is on a weekend, update it again by adding either one day or two days to make it a weekday. - NOTE: Does not take official holidays into account.
const addWeekDays = (startDate, count) =>
Array.from({ length: count }).reduce((date) => {
date = new Date(date.setDate(date.getDate() + 1));
if (date.getDay() % 6 === 0)
date = new Date(date.setDate(date.getDate() + (date.getDay() / 6 + 1)));
return date;
}, startDate);
addWeekDays(new Date("Oct 09, 2020"), 5); // 'Oct 16, 2020'
addWeekDays(new Date("Oct 12, 2020"), 5); // 'Oct 19, 2020'
Checks if the provided predicate function returns true
for all elements in a collection.
- Use
Array.prototype.every()
to test if all elements in the collection returntrue
based onfn
. - Omit the second argument,
fn
, to useBoolean
as a default.
const all = (arr, fn = Boolean) => arr.every(fn);
all([4, 2, 3], (x) => x > 1); // true
all([1, 2, 3]); // true
Checks if all elements in an array are equal.
- Use
Array.prototype.every()
to check if all the elements of the array are the same as the first one. - Elements in the array are compared using the strict comparison operator, which does not account for
NaN
self-inequality.
const allEqual = (arr) => arr.every((val) => val === arr[0]);
allEqual([1, 2, 3, 4, 5, 6]); // false
allEqual([1, 1, 1, 1]); // true
Checks if all elements in an array are equal, based on the provided mapping function.
- Apply
fn
to the first element ofarr
. - Use
Array.prototype.every()
to check iffn
returns the same value for all elements in the array as it did for the first one. - Elements in the array are compared using the strict comparison operator, which does not account for
NaN
self-inequality.
const allEqualBy = (arr, fn) => {
const eql = fn(arr[0]);
return arr.every((val) => fn(val) === eql);
};
allEqualBy([1.1, 1.2, 1.3], Math.round); // true
allEqualBy([1.1, 1.3, 1.6], Math.round); // false
Checks if all elements in an array are unique.
- Create a new
Set
from the mapped values to keep only unique occurrences. - Use
Array.prototype.length
andSet.prototype.size
to compare the length of the unique values to the original array.
const allUnique = (arr) => arr.length === new Set(arr).size;
allUnique([1, 2, 3, 4]); // true
allUnique([1, 1, 2, 3]); // false
Checks if all elements in an array are unique, based on the provided mapping function.
- Use
Array.prototype.map()
to applyfn
to all elements inarr
. - Create a new
Set
from the mapped values to keep only unique occurrences. - Use
Array.prototype.length
andSet.prototype.size
to compare the length of the unique mapped values to the original array.
const allUniqueBy = (arr, fn) => arr.length === new Set(arr.map(fn)).size;
allUniqueBy([1.2, 2.4, 2.9], Math.round); // true
allUniqueBy([1.2, 2.3, 2.4], Math.round); // false
title: and unlisted: true
Checks if both arguments are true
.
- Use the logical and (
&&
) operator on the two given values.
const and = (a, b) => a && b;
and(true, true); // true
and(true, false); // false
and(false, false); // false
Checks if the provided predicate function returns true
for at least one element in a collection.
- Use
Array.prototype.some()
to test if any elements in the collection returntrue
based onfn
. - Omit the second argument,
fn
, to useBoolean
as a default.
const any = (arr, fn = Boolean) => arr.some(fn);
any([0, 1, 2, 0], (x) => x >= 2); // true
any([0, 0, 1, 0]); // true
Creates an array of n
-tuples of consecutive elements.
- Use
Array.prototype.slice()
andArray.prototype.map()
to create an array of appropriate length. - Populate the array with
n
-tuples of consecutive elements fromarr
. - If
n
is greater than the length ofarr
, return an empty array.
const aperture = (n, arr) =>
n > arr.length ? [] : arr.slice(n - 1).map((v, i) => arr.slice(i, i + n));
aperture(2, [1, 2, 3, 4]); // [[1, 2], [2, 3], [3, 4]]
aperture(3, [1, 2, 3, 4]); // [[1, 2, 3], [2, 3, 4]]
aperture(5, [1, 2, 3, 4]); // []
Checks if two numbers are approximately equal to each other.
- Use
Math.abs()
to compare the absolute difference of the two values toepsilon
. - Omit the third argument,
epsilon
, to use a default value of0.001
.
const approximatelyEqual = (v1, v2, epsilon = 0.001) =>
Math.abs(v1 - v2) < epsilon;
approximatelyEqual(Math.PI / 2.0, 1.5708); // true
Creates an array of numbers in the arithmetic progression, starting with the given positive integer and up to the specified limit.
- Use
Array.from()
to create an array of the desired length,lim/n
. Use a map function to fill it with the desired values in the given range.
const arithmeticProgression = (n, lim) =>
Array.from({ length: Math.ceil(lim / n) }, (_, i) => (i + 1) * n);
arithmeticProgression(5, 25); // [5, 10, 15, 20, 25]
Converts a 2D array to a comma-separated values (CSV) string.
- Use
Array.prototype.map()
andArray.prototype.join(delimiter)
to combine individual 1D arrays (rows) into strings. - Use
Array.prototype.join('\n')
to combine all rows into a CSV string, separating each row with a newline. - Omit the second argument,
delimiter
, to use a default delimiter of,
.
const arrayToCSV = (arr, delimiter = ",") =>
arr
.map((v) =>
v
.map((x) => (isNaN(x) ? `"${x.replace(/"/g, '""')}"` : x))
.join(delimiter)
)
.join("\n");
arrayToCSV([
["a", "b"],
["c", "d"],
]); // '"a","b"\n"c","d"'
arrayToCSV(
[
["a", "b"],
["c", "d"],
],
";"
); // '"a";"b"\n"c";"d"'
arrayToCSV([
["a", '"b" great'],
["c", 3.1415],
]);
// '"a","""b"" great"\n"c",3.1415'
Converts the given array elements into <li>
tags and appends them to the list of the given id.
- Use
Array.prototype.map()
andDocument.querySelector()
to create a list of html tags.
const arrayToHTMLList = (arr, listID) =>
(document.querySelector(`#${listID}`).innerHTML += arr
.map((item) => `<li>${item}</li>`)
.join(""));
arrayToHTMLList(["item 1", "item 2"], "myListID");
Creates a function that accepts up to n
arguments, ignoring any additional arguments.
- Call the provided function,
fn
, with up ton
arguments, usingArray.prototype.slice(0, n)
and the spread operator (...
).
const ary =
(fn, n) =>
(...args) =>
fn(...args.slice(0, n));
const firstTwoMax = ary(Math.max, 2);
[[2, 6, "a"], [6, 4, 8], [10]].map((x) => firstTwoMax(...x)); // [6, 6, 10]
Validates all keys in an object match the given keys
.
- Use
Object.keys()
to get the keys of the given object,obj
. - Use
Array.prototype.every()
andArray.prototype.includes()
to validate that each key in the object is specified in thekeys
array.
const assertValidKeys = (obj, keys) =>
Object.keys(obj).every((key) => keys.includes(key));
assertValidKeys({ id: 10, name: "apple" }, ["id", "name"]); // true
assertValidKeys({ id: 10, name: "apple" }, ["id", "type"]); // false
Decodes a string of data which has been encoded using base-64 encoding.
- Create a
Buffer
for the given string with base-64 encoding and useBuffer.toString('binary')
to return the decoded string.
const atob = (str) => Buffer.from(str, "base64").toString("binary");
atob("Zm9vYmFy"); // 'foobar'
Attempts to invoke a function with the provided arguments, returning either the result or the caught error object.
- Use a
try... catch
block to return either the result of the function or an appropriate error. - If the caught object is not an
Error
, use it to create a newError
.
const attempt = (fn, ...args) => {
try {
return fn(...args);
} catch (e) {
return e instanceof Error ? e : new Error(e);
}
};
let elements = attempt(function (selector) {
return document.querySelectorAll(selector);
}, ">_>");
if (elements instanceof Error) elements = []; // elements = []
Calculates the average of two or more numbers.
- Use
Array.prototype.reduce()
to add each value to an accumulator, initialized with a value of0
. - Divide the resulting array by its length.
const average = (...nums) =>
nums.reduce((acc, val) => acc + val, 0) / nums.length;
average(...[1, 2, 3]); // 2
average(1, 2, 3); // 2
Calculates the average of an array, after mapping each element to a value using the provided function.
- Use
Array.prototype.map()
to map each element to the value returned byfn
. - Use
Array.prototype.reduce()
to add each value to an accumulator, initialized with a value of0
. - Divide the resulting array by its length.
const averageBy = (arr, fn) =>
arr
.map(typeof fn === "function" ? fn : (val) => val[fn])
.reduce((acc, val) => acc + val, 0) / arr.length;
averageBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], (o) => o.n); // 5
averageBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], "n"); // 5
Splits values into two groups, based on the result of the given filter
array.
- Use
Array.prototype.reduce()
andArray.prototype.push()
to add elements to groups, based onfilter
. - If
filter
has a truthy value for any element, add it to the first group, otherwise add it to the second group.
const bifurcate = (arr, filter) =>
arr.reduce(
(acc, val, i) => (acc[filter[i] ? 0 : 1].push(val), acc),
[[], []]
);
bifurcate(["beep", "boop", "foo", "bar"], [true, true, false, true]);
// [ ['beep', 'boop', 'bar'], ['foo'] ]
Splits values into two groups, based on the result of the given filtering function.
- Use
Array.prototype.reduce()
andArray.prototype.push()
to add elements to groups, based on the value returned byfn
for each element. - If
fn
returns a truthy value for any element, add it to the first group, otherwise add it to the second group.
const bifurcateBy = (arr, fn) =>
arr.reduce(
(acc, val, i) => (acc[fn(val, i) ? 0 : 1].push(val), acc),
[[], []]
);
bifurcateBy(["beep", "boop", "foo", "bar"], (x) => x[0] === "b");
// [ ['beep', 'boop', 'bar'], ['foo'] ]
Creates a function that accepts up to two arguments, ignoring any additional arguments.
- Call the provided function,
fn
, with the first two arguments given.
const binary = (fn) => (a, b) => fn(a, b);
["2", "1", "0"].map(binary(Math.max)); // [2, 1, 2]
Finds the index of a given element in a sorted array using the binary search algorithm.
- Declare the left and right search boundaries,
l
andr
, initialized to0
and thelength
of the array respectively. - Use a
while
loop to repeatedly narrow down the search subarray, usingMath.floor()
to cut it in half. - Return the index of the element if found, otherwise return
-1
. - Note: Does not account for duplicate values in the array.
const binarySearch = (arr, item) => {
let l = 0,
r = arr.length - 1;
while (l <= r) {
const mid = Math.floor((l + r) / 2);
const guess = arr[mid];
if (guess === item) return mid;
if (guess > item) r = mid - 1;
else l = mid + 1;
}
return -1;
};
binarySearch([1, 2, 3, 4, 5], 1); // 0
binarySearch([1, 2, 3, 4, 5], 5); // 4
binarySearch([1, 2, 3, 4, 5], 6); // -1
Creates a function that invokes fn
with a given context, optionally prepending any additional supplied parameters to the arguments.
- Return a
function
that usesFunction.prototype.apply()
to apply the givencontext
tofn
. - Use the spread operator (
...
) to prepend any additional supplied parameters to the arguments.
const bind =
(fn, context, ...boundArgs) =>
(...args) =>
fn.apply(context, [...boundArgs, ...args]);
function greet(greeting, punctuation) {
return greeting + " " + this.user + punctuation;
}
const freddy = { user: "fred" };
const freddyBound = bind(greet, freddy);
console.log(freddyBound("hi", "!")); // 'hi fred!'
Binds methods of an object to the object itself, overwriting the existing method.
- Use
Array.prototype.forEach()
to iterate over the givenfns
. - Return a function for each one, using
Function.prototype.apply()
to apply the given context (obj
) tofn
.
const bindAll = (obj, ...fns) =>
fns.forEach(
(fn) => (
(f = obj[fn]),
(obj[fn] = function () {
return f.apply(obj);
})
)
);
let view = {
label: "docs",
click: function () {
console.log("clicked " + this.label);
},
};
bindAll(view, "click");
document.body.addEventListener("click", view.click);
// Log 'clicked docs' when clicked.
Creates a function that invokes the method at a given key of an object, optionally prepending any additional supplied parameters to the arguments.
- Return a
function
that usesFunction.prototype.apply()
to bindcontext[fn]
tocontext
. - Use the spread operator (
...
) to prepend any additional supplied parameters to the arguments.
const bindKey =
(context, fn, ...boundArgs) =>
(...args) =>
context[fn].apply(context, [...boundArgs, ...args]);
const freddy = {
user: "fred",
greet: function (greeting, punctuation) {
return greeting + " " + this.user + punctuation;
},
};
const freddyBound = bindKey(freddy, "greet");
console.log(freddyBound("hi", "!")); // 'hi fred!'
Calculates the number of ways to choose k
items from n
items without repetition and without order.
- Use
Number.isNaN()
to check if any of the two values isNaN
. - Check if
k
is less than0
, greater than or equal ton
, equal to1
orn - 1
and return the appropriate result. - Check if
n - k
is less thank
and switch their values accordingly. - Loop from
2
throughk
and calculate the binomial coefficient. - Use
Math.round()
to account for rounding errors in the calculation.
const binomialCoefficient = (n, k) => {
if (Number.isNaN(n) || Number.isNaN(k)) return NaN;
if (k < 0 || k > n) return 0;
if (k === 0 || k === n) return 1;
if (k === 1 || k === n - 1) return n;
if (n - k < k) k = n - k;
let res = n;
for (let j = 2; j <= k; j++) res *= (n - j + 1) / j;
return Math.round(res);
};
binomialCoefficient(8, 2); // 28
title: both unlisted: true
Checks if both of the given functions return true
for a given set of arguments.
- Use the logical and (
&&
) operator on the result of calling the two functions with the suppliedargs
.
const both =
(f, g) =>
(...args) =>
f(...args) && g(...args);
const isEven = (num) => num % 2 === 0;
const isPositive = (num) => num > 0;
const isPositiveEven = both(isEven, isPositive);
isPositiveEven(4); // true
isPositiveEven(-2); // false
Widgets
chrome-extension://gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/Moat.svg
chrome-extension://gppongmhjkpfnbhagpmjfkannfbllamg/images/icons/Facebook.svg
Google Analytics](https://www.wappalyzer.com/technologies/analytics/google-analytics/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer)
Google Ads Conversion Tracking](https://www.wappalyzer.com/technologies/analytics/google-ads-conversion-tracking/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer)
Gatsby2.25.4](https://www.wappalyzer.com/technologies/javascript-frameworks/gatsby/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer)
Google Font API](https://www.wappalyzer.com/technologies/font-scripts/google-font-api/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer)
jQuery CDN](https://www.wappalyzer.com/technologies/cdn/jquery-cdn/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer)
Google AdSense](https://www.wappalyzer.com/technologies/advertising/google-adsense/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer)
Google Tag Manager](https://www.wappalyzer.com/technologies/tag-managers/google-tag-manager/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer)
Gatsby2.25.4](https://www.wappalyzer.com/technologies/static-site-generator/gatsby/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer)
Lodash4.17.11](https://www.wappalyzer.com/technologies/javascript-libraries/lodash/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer)
core-js3.10.2](https://www.wappalyzer.com/technologies/javascript-libraries/core-js/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer)
Bootstrap5.1.1](https://www.wappalyzer.com/technologies/ui-frameworks/bootstrap/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer)
Facebook Login](https://www.wappalyzer.com/technologies/authentication/facebook-login/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer)
Google Remarketing Tag](https://www.wappalyzer.com/technologies/retargeting/google-remarketing-tag/?utm_source=popup&utm_medium=extension&utm_campaign=wappalyzer)
Creates a base-64 encoded ASCII string from a String object in which each character in the string is treated as a byte of binary data.
- Create a
Buffer
for the given string with binary encoding and useBuffer.toString('base64')
to return the encoded string.
const btoa = (str) => Buffer.from(str, "binary").toString("base64");
btoa("foobar"); // 'Zm9vYmFy'
Sorts an array of numbers, using the bubble sort algorithm.
- Declare a variable,
swapped
, that indicates if any values were swapped during the current iteration. - Use the spread operator (
...
) to clone the original array,arr
. - Use a
for
loop to iterate over the elements of the cloned array, terminating before the last element. - Use a nested
for
loop to iterate over the segment of the array between0
andi
, swapping any adjacent out of order elements and settingswapped
totrue
. - If
swapped
isfalse
after an iteration, no more changes are needed, so the cloned array is returned.
const bubbleSort = (arr) => {
let swapped = false;
const a = [...arr];
for (let i = 1; i < a.length; i++) {
swapped = false;
for (let j = 0; j < a.length - i; j++) {
if (a[j + 1] < a[j]) {
[a[j], a[j + 1]] = [a[j + 1], a[j]];
swapped = true;
}
}
if (!swapped) return a;
}
return a;
};
bubbleSort([2, 1, 4, 3]); // [1, 2, 3, 4]
Sorts an array of numbers, using the bucket sort algorithm.
- Use
Math.min(),
Math.max()
and the spread operator (...
) to find the minimum and maximum values of the given array. - Use
Array.from()
andMath.floor()
to create the appropriate number ofbuckets
(empty arrays). - Use
Array.prototype.forEach()
to populate each bucket with the appropriate elements from the array. - Use
Array.prototype.reduce()
, the spread operator (...
) andArray.prototype.sort()
to sort each bucket and append it to the result.
const bucketSort = (arr, size = 5) => {
const min = Math.min(...arr);
const max = Math.max(...arr);
const buckets = Array.from(
{ length: Math.floor((max - min) / size) + 1 },
() => []
);
arr.forEach((val) => {
buckets[Math.floor((val - min) / size)].push(val);
});
return buckets.reduce((acc, b) => [...acc, ...b.sort((a, b) => a - b)], []);
};
bucketSort([6, 3, 4, 1]); // [1, 3, 4, 6]
Returns the length of a string in bytes.
- Convert a given string to a
Blob
Object. - Use
Blob.size
to get the length of the string in bytes.
const byteSize = (str) => new Blob([str]).size;
byteSize("😀"); // 4
byteSize("Hello World"); // 11
Encrypts or decrypts a given string using the Caesar cipher.
- Use the modulo (
%
) operator and the ternary operator (?
) to calculate the correct encryption/decryption key. - Use the spread operator (
...
) andArray.prototype.map()
to iterate over the letters of the given string. - Use
String.prototype.charCodeAt()
andString.fromCharCode()
to convert each letter appropriately, ignoring special characters, spaces etc. - Use
Array.prototype.join()
to combine all the letters into a string. - Pass
true
to the last parameter,decrypt
, to decrypt an encrypted string.
const caesarCipher = (str, shift, decrypt = false) => {
const s = decrypt ? (26 - shift) % 26 : shift;
const n = s > 0 ? s : 26 + (s % 26);
return [...str]
.map((l, i) => {
const c = str.charCodeAt(i);
if (c >= 65 && c <= 90)
return String.fromCharCode(((c - 65 + n) % 26) + 65);
if (c >= 97 && c <= 122)
return String.fromCharCode(((c - 97 + n) % 26) + 97);
return l;
})
.join("");
};
caesarCipher("Hello World!", -3); // 'Ebiil Tloia!'
caesarCipher("Ebiil Tloia!", 23, true); // 'Hello World!'
Given a key and a set of arguments, call them when given a context.
- Use a closure to call
key
withargs
for the givencontext
.
const call =
(key, ...args) =>
(context) =>
context[key](...args);
Promise.resolve([1, 2, 3])
.then(call("map", (x) => 2 * x))
.then(console.log); // [ 2, 4, 6 ]
const map = call.bind(null, "map");
Promise.resolve([1, 2, 3])
.then(map((x) => 2 * x))
.then(console.log); // [ 2, 4, 6 ]
Capitalizes the first letter of a string.
- Use array destructuring and
String.prototype.toUpperCase()
to capitalize the first letter of the string. - Use
Array.prototype.join('')
to combine the capitalizedfirst
with the...rest
of the characters. - Omit the
lowerRest
argument to keep the rest of the string intact, or set it totrue
to convert to lowercase.
const capitalize = ([first, ...rest], lowerRest = false) =>
first.toUpperCase() +
(lowerRest ? rest.join("").toLowerCase() : rest.join(""));
capitalize("fooBar"); // 'FooBar'
capitalize("fooBar", true); // 'Foobar'
Capitalizes the first letter of every word in a string.
- Use
String.prototype.replace()
to match the first character of each word andString.prototype.toUpperCase()
to capitalize it.
const capitalizeEveryWord = (str) =>
str.replace(/\b[a-z]/g, (char) => char.toUpperCase());
capitalizeEveryWord("hello world!"); // 'Hello World!'
Calculates the cartesian product of two arrays.
- Use
Array.prototype.reduce()
,Array.prototype.map()
and the spread operator (...
) to generate all possible element pairs from the two arrays.
const cartesianProduct = (a, b) =>
a.reduce((p, x) => [...p, ...b.map((y) => [x, y])], []);
cartesianProduct(["x", "y"], [1, 2]);
// [['x', 1], ['x', 2], ['y', 1], ['y', 2]]
Casts the provided value as an array if it's not one.
- Use
Array.prototype.isArray()
to determine ifval
is an array and return it as-is or encapsulated in an array accordingly.
const castArray = (val) => (Array.isArray(val) ? val : [val]);
castArray("foo"); // ['foo']
castArray([1]); // [1]
title: celsiusToFahrenheit unlisted: true
Converts Celsius to Fahrenheit.
- Follow the conversion formula
F = 1.8 * C + 32
.
const celsiusToFahrenheit = (degrees) => 1.8 * degrees + 32;
celsiusToFahrenheit(33); // 91.4
Chains asynchronous functions.
- Loop through an array of functions containing asynchronous events, calling
next
when each asynchronous event has completed.
const chainAsync = (fns) => {
let curr = 0;
const last = fns[fns.length - 1];
const next = () => {
const fn = fns[curr++];
fn === last ? fn() : fn(next);
};
next();
};
chainAsync([
(next) => {
console.log("0 seconds");
setTimeout(next, 1000);
},
(next) => {
console.log("1 second");
setTimeout(next, 1000);
},
() => {
console.log("2 second");
},
]);
Changes the lightness value of an hsl()
color string.
- Use
String.prototype.match()
to get an array of 3 strings with the numeric values. - Use
Array.prototype.map()
in combination withNumber
to convert them into an array of numeric values. - Make sure the lightness is within the valid range (between
0
and100
), usingMath.max()
andMath.min()
. - Use a template literal to create a new
hsl()
string with the updated value.
const changeLightness = (delta, hslStr) => {
const [hue, saturation, lightness] = hslStr.match(/\d+/g).map(Number);
const newLightness = Math.max(
0,
Math.min(100, lightness + parseFloat(delta))
);
return `hsl(${hue}, ${saturation}%, ${newLightness}%)`;
};
changeLightness(10, "hsl(330, 50%, 50%)"); // 'hsl(330, 50%, 60%)'
changeLightness(-10, "hsl(330, 50%, 50%)"); // 'hsl(330, 50%, 40%)'
Creates a function that will invoke a predicate function for the specified property on a given object.
- Return a curried function, that will invoke
predicate
for the specifiedprop
onobj
and return a boolean.
const checkProp = (predicate, prop) => (obj) => !!predicate(obj[prop]);
const lengthIs4 = checkProp((l) => l === 4, "length");
lengthIs4([]); // false
lengthIs4([1, 2, 3, 4]); // true
lengthIs4(new Set([1, 2, 3, 4])); // false (Set uses Size, not length)
const session = { user: {} };
const validUserSession = checkProp((u) => u.active && !u.disabled, "user");
validUserSession(session); // false
session.user.active = true;
validUserSession(session); // true
const noLength = checkProp((l) => l === undefined, "length");
noLength([]); // false
noLength({}); // true
noLength(new Set()); // true
Chunks an array into smaller arrays of a specified size.
- Use
Array.from()
to create a new array, that fits the number of chunks that will be produced. - Use
Array.prototype.slice()
to map each element of the new array to a chunk the length ofsize
. - If the original array can't be split evenly, the final chunk will contain the remaining elements.
const chunk = (arr, size) =>
Array.from({ length: Math.ceil(arr.length / size) }, (v, i) =>
arr.slice(i * size, i * size + size)
);
chunk([1, 2, 3, 4, 5], 2); // [[1, 2], [3, 4], [5]]
Chunks an array into n
smaller arrays.
- Use
Math.ceil()
andArray.prototype.length
to get the size of each chunk. - Use
Array.from()
to create a new array of sizen
. - Use
Array.prototype.slice()
to map each element of the new array to a chunk the length ofsize
. - If the original array can't be split evenly, the final chunk will contain the remaining elements.
const chunkIntoN = (arr, n) => {
const size = Math.ceil(arr.length / n);
return Array.from({ length: n }, (v, i) =>
arr.slice(i * size, i * size + size)
);
};
chunkIntoN([1, 2, 3, 4, 5, 6, 7], 4); // [[1, 2], [3, 4], [5, 6], [7]]
Chunks an iterable into smaller arrays of a specified size.
- Use a
for...of
loop over the given iterable, usingArray.prototype.push()
to add each new value to the currentchunk
. - Use
Array.prototype.length
to check if the currentchunk
is of the desiredsize
andyield
the value if it is. - Finally, use
Array.prototype.length
to check the finalchunk
andyield
it if it's non-empty.
const chunkify = function* (itr, size) {
let chunk = [];
for (const v of itr) {
chunk.push(v);
if (chunk.length === size) {
yield chunk;
chunk = [];
}
}
if (chunk.length) yield chunk;
};
const x = new Set([1, 2, 1, 3, 4, 1, 2, 5]);
[...chunkify(x, 2)]; // [[1, 2], [3, 4], [5]]
Clamps num
within the inclusive range specified by the boundary values a
and b
.
- If
num
falls within the range, returnnum
. - Otherwise, return the nearest number in the range.
const clampNumber = (num, a, b) =>
Math.max(Math.min(num, Math.max(a, b)), Math.min(a, b));
clampNumber(2, 3, 5); // 3
clampNumber(1, -1, -5); // -1
Clones a regular expression.
- Use
new RegExp()
,RegExp.prototype.source
andRegExp.prototype.flags
to clone the given regular expression.
const cloneRegExp = (regExp) => new RegExp(regExp.source, regExp.flags);
const regExp = /lorem ipsum/gi;
const regExp2 = cloneRegExp(regExp); // regExp !== regExp2
Returns the first defined, non-null argument.
- Use
Array.prototype.find()
andArray.prototype.includes()
to find the first value that is not equal toundefined
ornull
.
const coalesce = (...args) => args.find((v) => ![undefined, null].includes(v));
coalesce(null, undefined, "", NaN, "Waldo"); // ''
Customizes a coalesce function that returns the first argument which is true based on the given validator.
- Use
Array.prototype.find()
to return the first argument that returnstrue
from the provided argument validation function,valid
.
const coalesceFactory =
(valid) =>
(...args) =>
args.find(valid);
const customCoalesce = coalesceFactory(
(v) => ![null, undefined, "", NaN].includes(v)
);
customCoalesce(undefined, null, NaN, "", "Waldo"); // 'Waldo'
Changes a function that accepts an array into a variadic function.
- Given a function, return a closure that collects all inputs into an array-accepting function.
const collectInto =
(fn) =>
(...args) =>
fn(args);
const Pall = collectInto(Promise.all.bind(Promise));
let p1 = Promise.resolve(1);
let p2 = Promise.resolve(2);
let p3 = new Promise((resolve) => setTimeout(resolve, 2000, 3));
Pall(p1, p2, p3).then(console.log); // [1, 2, 3] (after about 2 seconds)
Adds special characters to text to print in color in the console (combined with console.log()
).
- Use template literals and special characters to add the appropriate color code to the string output.
- For background colors, add a special character that resets the background color at the end of the string.
const colorize = (...args) => ({
black: `\x1b[30m${args.join(" ")}`,
red: `\x1b[31m${args.join(" ")}`,
green: `\x1b[32m${args.join(" ")}`,
yellow: `\x1b[33m${args.join(" ")}`,
blue: `\x1b[34m${args.join(" ")}`,
magenta: `\x1b[35m${args.join(" ")}`,
cyan: `\x1b[36m${args.join(" ")}`,
white: `\x1b[37m${args.join(" ")}`,
bgBlack: `\x1b[40m${args.join(" ")}\x1b[0m`,
bgRed: `\x1b[41m${args.join(" ")}\x1b[0m`,
bgGreen: `\x1b[42m${args.join(" ")}\x1b[0m`,
bgYellow: `\x1b[43m${args.join(" ")}\x1b[0m`,
bgBlue: `\x1b[44m${args.join(" ")}\x1b[0m`,
bgMagenta: `\x1b[45m${args.join(" ")}\x1b[0m`,
bgCyan: `\x1b[46m${args.join(" ")}\x1b[0m`,
bgWhite: `\x1b[47m${args.join(" ")}\x1b[0m`,
});
console.log(colorize("foo").red); // 'foo' (red letters)
console.log(colorize("foo", "bar").bgBlue); // 'foo bar' (blue background)
console.log(colorize(colorize("foo").yellow, colorize("foo").green).bgWhite);
// 'foo bar' (first word in yellow letters, second word in green letters, white background for both)
Combines two arrays of objects, using the specified key to match objects.
- Use
Array.prototype.reduce()
with an object accumulator to combine all objects in both arrays based on the givenprop
. - Use
Object.values()
to convert the resulting object to an array and return it.
const combine = (a, b, prop) =>
Object.values(
[...a, ...b].reduce((acc, v) => {
if (v[prop])
acc[v[prop]] = acc[v[prop]] ? { ...acc[v[prop]], ...v } : { ...v };
return acc;
}, {})
);
const x = [
{ id: 1, name: "John" },
{ id: 2, name: "Maria" },
];
const y = [{ id: 1, age: 28 }, { id: 3, age: 26 }, { age: 3 }];
combine(x, y, "id");
// [
// { id: 1, name: 'John', age: 28 },
// { id: 2, name: 'Maria' },
// { id: 3, age: 26 }
// ]
Removes falsy values from an array.
- Use
Array.prototype.filter()
to filter out falsy values (false
,null
,0
,""
,undefined
, andNaN
).
const compact = (arr) => arr.filter(Boolean);
compact([0, 1, false, 2, "", 3, "a", "e" * 23, NaN, "s", 34]);
// [ 1, 2, 3, 'a', 's', 34 ]
Deeply removes all falsy values from an object or array.
- Use recursion.
- Initialize the iterable data, using
Array.isArray()
,Array.prototype.filter()
andBoolean
for arrays in order to avoid sparse arrays. - Use
Object.keys()
andArray.prototype.reduce()
to iterate over each key with an appropriate initial value. - Use
Boolean
to determine the truthiness of each key's value and add it to the accumulator if it's truthy. - Use
typeof
to determine if a given value is anobject
and call the function again to deeply compact it.
const compactObject = (val) => {
const data = Array.isArray(val) ? val.filter(Boolean) : val;
return Object.keys(data).reduce(
(acc, key) => {
const value = data[key];
if (Boolean(value))
acc[key] = typeof value === "object" ? compactObject(value) : value;
return acc;
},
Array.isArray(val) ? [] : {}
);
};
const obj = {
a: null,
b: false,
c: true,
d: 0,
e: 1,
f: "",
g: "a",
h: [null, false, "", true, 1, "a"],
i: { j: 0, k: false, l: "a" },
};
compactObject(obj);
// { c: true, e: 1, g: 'a', h: [ true, 1, 'a' ], i: { l: 'a' } }
Compacts whitespaces in a string.
- Use
String.prototype.replace()
with a regular expression to replace all occurrences of 2 or more whitespace characters with a single space.
const compactWhitespace = (str) => str.replace(/\s{2,}/g, " ");
compactWhitespace("Lorem Ipsum"); // 'Lorem Ipsum'
compactWhitespace("Lorem \n Ipsum"); // 'Lorem Ipsum'
Returns a function that is the logical complement of the given function, fn
.
- Use the logical not (
!
) operator on the result of callingfn
with any suppliedargs
.
const complement =
(fn) =>
(...args) =>
!fn(...args);
const isEven = (num) => num % 2 === 0;
const isOdd = complement(isEven);
isOdd(2); // false
isOdd(3); // true
Performs right-to-left function composition.
- Use
Array.prototype.reduce()
to perform right-to-left function composition. - The last (rightmost) function can accept one or more arguments; the remaining functions must be unary.
const compose = (...fns) =>
fns.reduce(
(f, g) =>
(...args) =>
f(g(...args))
);
const add5 = (x) => x + 5;
const multiply = (x, y) => x * y;
const multiplyAndAdd5 = compose(add5, multiply);
multiplyAndAdd5(5, 2); // 15
Performs left-to-right function composition.
- Use
Array.prototype.reduce()
to perform left-to-right function composition. - The first (leftmost) function can accept one or more arguments; the remaining functions must be unary.
const composeRight = (...fns) =>
fns.reduce(
(f, g) =>
(...args) =>
g(f(...args))
);
const add = (x, y) => x + y;
const square = (x) => x * x;
const addAndSquare = composeRight(add, square);
addAndSquare(1, 2); // 9
Checks if the given string contains any whitespace characters.
- Use
RegExp.prototype.test()
with an appropriate regular expression to check if the given string contains any whitespace characters.
const containsWhitespace = (str) => /\s/.test(str);
containsWhitespace("lorem"); // false
containsWhitespace("lorem ipsum"); // true
Accepts a converging function and a list of branching functions and returns a function that applies each branching function to the arguments and the results of the branching functions are passed as arguments to the converging function.
- Use
Array.prototype.map()
andFunction.prototype.apply()
to apply each function to the given arguments. - Use the spread operator (
...
) to callconverger
with the results of all other functions.
const converge =
(converger, fns) =>
(...args) =>
converger(...fns.map((fn) => fn.apply(null, args)));
const average = converge(
(a, b) => a / b,
[(arr) => arr.reduce((a, v) => a + v, 0), (arr) => arr.length]
);
average([1, 2, 3, 4, 5, 6, 7]); // 4
Returns the absolute value of the first number, but the sign of the second.
- Use
Math.sign()
to check if the two numbers have the same sign. - Return
x
if they do,-x
otherwise.
const copySign = (x, y) => (Math.sign(x) === Math.sign(y) ? x : -x);
copySign(2, 3); // 2
copySign(2, -3); // -2
copySign(-2, 3); // 2
copySign(-2, -3); // -2
Copies a string to the clipboard.
Only works as a result of user action (i.e. inside a click
event listener).
- Create a new
<textarea>
element, fill it with the supplied data and add it to the HTML document. - Use
Selection.getRangeAt()
to store the selected range (if any). - Use
Document.execCommand('copy')
to copy to the clipboard. - Remove the
<textarea>
element from the HTML document. - Finally, use
Selection().addRange()
to recover the original selected range (if any). - Note: You can use the new asynchronous Clipboard API to implement the same functionality. It's experimental but should be used in the future instead of this snippet. Find out more about it here.
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);
}
};
copyToClipboard("Lorem ipsum"); // 'Lorem ipsum' copied to clipboard.
Groups the elements of an array based on the given function and returns the count of elements in each group.
- Use
Array.prototype.map()
to map the values of an array to a function or property name. - Use
Array.prototype.reduce()
to create an object, where the keys are produced from the mapped results.
const countBy = (arr, fn) =>
arr
.map(typeof fn === "function" ? fn : (val) => val[fn])
.reduce((acc, val) => {
acc[val] = (acc[val] || 0) + 1;
return acc;
}, {});
countBy([6.1, 4.2, 6.3], Math.floor); // {4: 1, 6: 2}
countBy(["one", "two", "three"], "length"); // {3: 2, 5: 1}
countBy([{ count: 5 }, { count: 10 }, { count: 5 }], (x) => x.count);
// {5: 2, 10: 1}
Counts the occurrences of a value in an array.
- Use
Array.prototype.reduce()
to increment a counter each time the specific value is encountered inside the array.
const countOccurrences = (arr, val) =>
arr.reduce((a, v) => (v === val ? a + 1 : a), 0);
countOccurrences([1, 1, 2, 1, 2, 3], 1); // 3
Counts the occurrences of a substring in a given string.
- Use
Array.prototype.indexOf()
to look forsearchValue
instr
. - Increment a counter if the value is found and update the index,
i
. - Use a
while
loop that will return as soon as the value returned fromArray.prototype.indexOf()
is-1
.
const countSubstrings = (str, searchValue) => {
let count = 0,
i = 0;
while (true) {
const r = str.indexOf(searchValue, i);
if (r !== -1) [count, i] = [count + 1, r + 1];
else return count;
}
};
countSubstrings("tiktok tok tok tik tok tik", "tik"); // 3
countSubstrings("tutut tut tut", "tut"); // 4
Counts the weekdays between two dates.
- Use
Array.from()
to construct an array withlength
equal to the number of days betweenstartDate
andendDate
. - Use
Array.prototype.reduce()
to iterate over the array, checking if each date is a weekday and incrementingcount
. - Update
startDate
with the next day each loop usingDate.prototype.getDate()
andDate.prototype.setDate()
to advance it by one day. - NOTE: Does not take official holidays into account.
const countWeekDaysBetween = (startDate, endDate) =>
Array.from({ length: (endDate - startDate) / (1000 * 3600 * 24) }).reduce(
(count) => {
if (startDate.getDay() % 6 !== 0) count++;
startDate = new Date(startDate.setDate(startDate.getDate() + 1));
return count;
},
0
);
countWeekDaysBetween(new Date("Oct 05, 2020"), new Date("Oct 06, 2020")); // 1
countWeekDaysBetween(new Date("Oct 05, 2020"), new Date("Oct 14, 2020")); // 7
Creates a counter with the specified range, step and duration for the specified selector.
- Check if
step
has the proper sign and change it accordingly. - Use
setInterval()
in combination withMath.abs()
andMath.floor()
to calculate the time between each new text draw. - Use
Document.querySelector()
,Element.innerHTML
to update the value of the selected element. - Omit the fourth argument,
step
, to use a default step of1
. - Omit the fifth argument,
duration
, to use a default duration of2000
ms.
const counter = (selector, start, end, step = 1, duration = 2000) => {
let current = start,
_step = (end - start) * step < 0 ? -step : step,
timer = setInterval(() => {
current += _step;
document.querySelector(selector).innerHTML = current;
if (current >= end) document.querySelector(selector).innerHTML = end;
if (current >= end) clearInterval(timer);
}, Math.abs(Math.floor(duration / (end - start))));
return timer;
};
counter("#my-id", 1, 1000, 5, 2000);
// Creates a 2-second timer for the element with id="my-id"
Creates a directory, if it does not exist.
- Use
fs.existsSync()
to check if the directory exists,fs.mkdirSync()
to create it.
const fs = require("fs");
const createDirIfNotExists = (dir) =>
!fs.existsSync(dir) ? fs.mkdirSync(dir) : undefined;
createDirIfNotExists("test");
// creates the directory 'test', if it doesn't exist
Creates an element from a string (without appending it to the document). If the given string contains multiple elements, only the first one will be returned.
- Use
Document.createElement()
to create a new element. - Use
Element.innerHTML
to set its inner HTML to the string supplied as the argument. - Use
ParentNode.firstElementChild
to return the element version of the string.
const createElement = (str) => {
const el = document.createElement("div");
el.innerHTML = str;
return el.firstElementChild;
};
const el = createElement(
`<div class="container">
<p>Hello!</p>
</div>`
);
console.log(el.className); // 'container'
Creates a pub/sub (publish–subscribe) event hub with emit
, on
, and off
methods.
- Use
Object.create(null)
to create an emptyhub
object that does not inherit properties fromObject.prototype
. - For
emit
, resolve the array of handlers based on theevent
argument and then run each one withArray.prototype.forEach()
by passing in the data as an argument. - For
on
, create an array for the event if it does not yet exist, then useArray.prototype.push()
to add the handler - to the array.
- For
off
, useArray.prototype.findIndex()
to find the index of the handler in the event array and remove it usingArray.prototype.splice()
.
const createEventHub = () => ({
hub: Object.create(null),
emit(event, data) {
(this.hub[event] || []).forEach((handler) => handler(data));
},
on(event, handler) {
if (!this.hub[event]) this.hub[event] = [];
this.hub[event].push(handler);
},
off(event, handler) {
const i = (this.hub[event] || []).findIndex((h) => h === handler);
if (i > -1) this.hub[event].splice(i, 1);
if (this.hub[event].length === 0) delete this.hub[event];
},
});
const handler = (data) => console.log(data);
const hub = createEventHub();
let increment = 0;
// Subscribe: listen for different types of events
hub.on("message", handler);
hub.on("message", () => console.log("Message event fired"));
hub.on("increment", () => increment++);
// Publish: emit events to invoke all handlers subscribed to them, passing the data to them as an argument
hub.emit("message", "hello world"); // logs 'hello world' and 'Message event fired'
hub.emit("message", { hello: "world" }); // logs the object and 'Message event fired'
hub.emit("increment"); // `increment` variable is now 1
// Unsubscribe: stop a specific handler from listening to the 'message' event
hub.off("message", handler);
Returns the current URL.
- Use
Window.location.href
to get the current URL.
const currentURL = () => window.location.href;
currentURL(); // 'https://www.google.com/'
Curries a function.
- Use recursion.
- If the number of provided arguments (
args
) is sufficient, call the passed functionfn
. - Otherwise, use
Function.prototype.bind()
to return a curried functionfn
that expects the rest of the arguments. - If you want to curry a function that accepts a variable number of arguments (a variadic function, e.g.
Math.min()
), you can optionally pass the number of arguments to the second parameterarity
.
const curry = (fn, arity = fn.length, ...args) =>
arity <= args.length ? fn(...args) : curry.bind(null, fn, arity, ...args);
curry(Math.pow)(2)(10); // 1024
curry(Math.min, 3)(10)(50)(2); // 2
Creates a generator, looping over the given array indefinitely.
- Use a non-terminating
while
loop, that willyield
a value every timeGenerator.prototype.next()
is called. - Use the module operator (
%
) withArray.prototype.length
to get the next value's index and increment the counter after eachyield
statement.
const cycleGenerator = function* (arr) {
let i = 0;
while (true) {
yield arr[i % arr.length];
i++;
}
};
const binaryCycle = cycleGenerator([0, 1]);
binaryCycle.next(); // { value: 0, done: false }
binaryCycle.next(); // { value: 1, done: false }
binaryCycle.next(); // { value: 0, done: false }
binaryCycle.next(); // { value: 1, done: false }
Creates a generator, that generates all dates in the given range using the given step.
- Use a
while
loop to iterate fromstart
toend
, usingyield
to return each date in the range, using theDate
constructor. - Use
Date.prototype.getDate()
andDate.prototype.setDate()
to increment bystep
days after returning each subsequent value. - Omit the third argument,
step
, to use a default value of1
.
const dateRangeGenerator = function* (start, end, step = 1) {
let d = start;
while (d < end) {
yield new Date(d);
d.setDate(d.getDate() + step);
}
};
[...dateRangeGenerator(new Date("2021-06-01"), new Date("2021-06-04"))];
// [ 2021-06-01, 2021-06-02, 2021-06-03 ]
Gets the name of the weekday from a Date
object.
- Use
Date.prototype.toLocaleDateString()
with the{ weekday: 'long' }
option to retrieve the weekday. - Use the optional second argument to get a language-specific name or omit it to use the default locale.
const dayName = (date, locale) =>
date.toLocaleDateString(locale, { weekday: "long" });
dayName(new Date()); // 'Saturday'
dayName(new Date("09/23/2020"), "de-DE"); // 'Samstag'
Gets the day of the year (number in the range 1-366) from a Date
object.
- Use
new Date()
andDate.prototype.getFullYear()
to get the first day of the year as aDate
object. - Subtract the first day of the year from
date
and divide with the milliseconds in each day to get the result. - Use
Math.floor()
to appropriately round the resulting day count to an integer.
const dayOfYear = (date) =>
Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24);
dayOfYear(new Date()); // 272
Calculates the date of n
days ago from today as a string representation.
- Use
new Date()
to get the current date,Math.abs()
andDate.prototype.getDate()
to update the date accordingly and set to the result usingDate.prototype.setDate()
. - Use
Date.prototype.toISOString()
to return a string inyyyy-mm-dd
format.
const daysAgo = (n) => {
let d = new Date();
d.setDate(d.getDate() - Math.abs(n));
return d.toISOString().split("T")[0];
};
daysAgo(20); // 2020-09-16 (if current date is 2020-10-06)
Calculates the date of n
days from today as a string representation.
- Use
new Date()
to get the current date,Math.abs()
andDate.prototype.getDate()
to update the date accordingly and set to the result usingDate.prototype.setDate()
. - Use
Date.prototype.toISOString()
to return a string inyyyy-mm-dd
format.
const daysFromNow = (n) => {
let d = new Date();
d.setDate(d.getDate() + Math.abs(n));
return d.toISOString().split("T")[0];
};
daysFromNow(5); // 2020-10-13 (if current date is 2020-10-08)
Gets the number of days in the given month
of the specified year
.
- Use the
new Date()
constructor to create a date from the givenyear
andmonth
. - Set the days parameter to
0
to get the last day of the previous month, as months are zero-indexed. - Use
Date.prototype.getDate()
to return the number of days in the givenmonth
.
const daysInMonth = (year, month) => new Date(year, month, 0).getDate();
daysInMonth(2020, 12)); // 31
daysInMonth(2024, 2)); // 29
Creates a debounced function that delays invoking the provided function until at least ms
milliseconds have elapsed since its last invocation.
- Each time the debounced function is invoked, clear the current pending timeout with
clearTimeout()
. UsesetTimeout()
to create a new timeout that delays invoking the function until at leastms
milliseconds have elapsed. - Use
Function.prototype.apply()
to apply thethis
context to the function and provide the necessary arguments. - Omit the second argument,
ms
, to set the timeout at a default of0
ms.
const debounce = (fn, ms = 0) => {
let timeoutId;
return function (...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn.apply(this, args), ms);
};
};
window.addEventListener(
"resize",
debounce(() => {
console.log(window.innerWidth);
console.log(window.innerHeight);
}, 250)
); // Will log the window dimensions at most every 250ms
Creates a debounced function that returns a promise, but delays invoking the provided function until at least ms
milliseconds have elapsed since the last time it was invoked.
All promises returned during this time will return the same data.
- Each time the debounced function is invoked, clear the current pending timeout with
clearTimeout()
and usesetTimeout()
to create a new timeout that delays invoking the function until at leastms
milliseconds has elapsed. - Use
Function.prototype.apply()
to apply thethis
context to the function and provide the necessary arguments. - Create a new
Promise
and add itsresolve
andreject
callbacks to thepending
promises stack. - When
setTimeout
is called, copy the current stack (as it can change between the provided function call and its resolution), clear it and call the provided function. - When the provided function resolves/rejects, resolve/reject all promises in the stack (copied when the function was called) with the returned data.
- Omit the second argument,
ms
, to set the timeout at a default of0
ms.
const debouncePromise = (fn, ms = 0) => {
let timeoutId;
const pending = [];
return (...args) =>
new Promise((res, rej) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
const currentPending = [...pending];
pending.length = 0;
Promise.resolve(fn.apply(this, args)).then(
(data) => {
currentPending.forEach(({ resolve }) => resolve(data));
},
(error) => {
currentPending.forEach(({ reject }) => reject(error));
}
);
}, ms);
pending.push({ resolve: res, reject: rej });
});
};
const fn = (arg) =>
new Promise((resolve) => {
setTimeout(resolve, 1000, ["resolved", arg]);
});
const debounced = debouncePromise(fn, 200);
debounced("foo").then(console.log);
debounced("bar").then(console.log);
// Will log ['resolved', 'bar'] both times
Decapitalizes the first letter of a string.
- Use array destructuring and
String.prototype.toLowerCase()
to decapitalize first letter,...rest
to get array of characters after first letter and thenArray.prototype.join('')
to make it a string again. - Omit the
upperRest
argument to keep the rest of the string intact, or set it totrue
to convert to uppercase.
const decapitalize = ([first, ...rest], upperRest = false) =>
first.toLowerCase() +
(upperRest ? rest.join("").toUpperCase() : rest.join(""));
decapitalize("FooBar"); // 'fooBar'
decapitalize("FooBar", true); // 'fOOBAR'
Creates a deep clone of an object. Clones primitives, arrays and objects, excluding class instances.
- Use recursion.
- Check if the passed object is
null
and, if so, returnnull
. - Use
Object.assign()
and an empty object ({}
) to create a shallow clone of the original. - Use
Object.keys()
andArray.prototype.forEach()
to determine which key-value pairs need to be deep cloned. - If the object is an
Array
, set theclone
'slength
to that of the original and useArray.from(clone)
to create a clone.
const deepClone = (obj) => {
if (obj === null) return null;
let clone = Object.assign({}, obj);
Object.keys(clone).forEach(
(key) =>
(clone[key] =
typeof obj[key] === "object" ? deepClone(obj[key]) : obj[key])
);
if (Array.isArray(obj)) {
clone.length = obj.length;
return Array.from(clone);
}
return clone;
};
const a = { foo: "bar", obj: { a: 1, b: 2 } };
const b = deepClone(a); // a !== b, a.obj !== b.obj
Deep flattens an array.
- Use recursion.
- Use
Array.prototype.concat()
with an empty array ([]
) and the spread operator (...
) to flatten an array. - Recursively flatten each element that is an array.
const deepFlatten = (arr) =>
[].concat(...arr.map((v) => (Array.isArray(v) ? deepFlatten(v) : v)));
deepFlatten([1, [2], [[3], 4], 5]); // [1, 2, 3, 4, 5]
Deep freezes an object.
- Use
Object.keys()
to get all the properties of the passed object,Array.prototype.forEach()
to iterate over them. - Call
Object.freeze(obj)
recursively on all properties, applyingdeepFreeze()
as necessary. - Finally, use
Object.freeze()
to freeze the given object.
const deepFreeze = (obj) => {
Object.keys(obj).forEach((prop) => {
if (typeof obj[prop] === "object") deepFreeze(obj[prop]);
});
return Object.freeze(obj);
};
"use strict";
const val = deepFreeze([1, [2, 3]]);
val[0] = 3; // not allowed
val[1][0] = 4; // not allowed as well
Gets the target value in a nested JSON object, based on the keys
array.
- Compare the keys you want in the nested JSON object as an
Array
. - Use
Array.prototype.reduce()
to get the values in the nested JSON object one by one. - If the key exists in the object, return the target value, otherwise return
null
.
const deepGet = (obj, keys) =>
keys.reduce(
(xs, x) => (xs && xs[x] !== null && xs[x] !== undefined ? xs[x] : null),
obj
);
let index = 2;
const data = {
foo: {
foz: [1, 2, 3],
bar: {
baz: ["a", "b", "c"],
},
},
};
deepGet(data, ["foo", "foz", index]); // get 3
deepGet(data, ["foo", "bar", "baz", 8, "foz"]); // null
Deep maps an object's keys.
- Creates an object with the same values as the provided object and keys generated by running the provided function for each key.
- Use
Object.keys(obj)
to iterate over the object's keys. - Use
Array.prototype.reduce()
to create a new object with the same values and mapped keys usingfn
.
const deepMapKeys = (obj, fn) =>
Array.isArray(obj)
? obj.map((val) => deepMapKeys(val, fn))
: typeof obj === "object"
? Object.keys(obj).reduce((acc, current) => {
const key = fn(current);
const val = obj[current];
acc[key] =
val !== null && typeof val === "object" ? deepMapKeys(val, fn) : val;
return acc;
}, {})
: obj;
const obj = {
foo: "1",
nested: {
child: {
withArray: [
{
grandChild: ["hello"],
},
],
},
},
};
const upperKeysObj = deepMapKeys(obj, (key) => key.toUpperCase());
/*
{
"FOO":"1",
"NESTED":{
"CHILD":{
"WITHARRAY":[
{
"GRANDCHILD":[ 'hello' ]
}
]
}
}
}
*/
Deeply merges two objects, using a function to handle keys present in both.
- Use
Object.keys()
to get the keys of both objects, create aSet
from them and use the spread operator (...
) to create an array of all the unique keys. - Use
Array.prototype.reduce()
to add each unique key to the object, usingfn
to combine the values of the two given objects.
const deepMerge = (a, b, fn) =>
[...new Set([...Object.keys(a), ...Object.keys(b)])].reduce(
(acc, key) => ({ ...acc, [key]: fn(key, a[key], b[key]) }),
{}
);
deepMerge(
{ a: true, b: { c: [1, 2, 3] } },
{ a: false, b: { d: [1, 2, 3] } },
(key, a, b) => (key === "a" ? a && b : Object.assign({}, a, b))
);
// { a: false, b: { c: [ 1, 2, 3 ], d: [ 1, 2, 3 ] } }
Assigns default values for all properties in an object that are undefined
.
- Use
Object.assign()
to create a new empty object and copy the original one to maintain key order. - Use
Array.prototype.reverse()
and the spread operator (...
) to combine the default values from left to right. - Finally, use
obj
again to overwrite properties that originally had a value.
const defaults = (obj, ...defs) =>
Object.assign({}, obj, ...defs.reverse(), obj);
defaults({ a: 1 }, { b: 2 }, { b: 6 }, { a: 3 }); // { a: 1, b: 2 }
Defers invoking a function until the current call stack has cleared.
- Use
setTimeout()
with a timeout of1
ms to add a new event to the event queue and allow the rendering engine to complete its work. - Use the spread (
...
) operator to supply the function with an arbitrary number of arguments.
const defer = (fn, ...args) => setTimeout(fn, 1, ...args);
// Example A:
defer(console.log, "a"), console.log("b"); // logs 'b' then 'a'
// Example B:
document.querySelector("#someElement").innerHTML = "Hello";
longRunningFunction();
// Browser will not update the HTML until this has finished
defer(longRunningFunction);
// Browser will update the HTML then run the function
Converts an angle from degrees to radians.
- Use
Math.PI
and the degree to radian formula to convert the angle from degrees to radians.
const degreesToRads = (deg) => (deg * Math.PI) / 180.0;
degreesToRads(90.0); // ~1.5708
Invokes the provided function after ms
milliseconds.
- Use
setTimeout()
to delay execution offn
. - Use the spread (
...
) operator to supply the function with an arbitrary number of arguments.
const delay = (fn, ms, ...args) => setTimeout(fn, ms, ...args);
delay(
function (text) {
console.log(text);
},
1000,
"later"
); // Logs 'later' after one second.
Detects whether the page is being viewed on a mobile device or a desktop.
- Use a regular expression to test the
navigator.userAgent
property to figure out if the device is a mobile device or a desktop.
const detectDeviceType = () =>
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
navigator.userAgent
)
? "Mobile"
: "Desktop";
detectDeviceType(); // 'Mobile' or 'Desktop'
Detects the preferred language of the current user.
- Use
NavigationLanguage.language
or the firstNavigationLanguage.languages
if available, otherwise returndefaultLang
. - Omit the second argument,
defaultLang
, to use'en-US'
as the default language code.
const detectLanguage = (defaultLang = "en-US") =>
navigator.language ||
(Array.isArray(navigator.languages) && navigator.languages[0]) ||
defaultLang;
detectLanguage(); // 'nl-NL'
Calculates the difference between two arrays, without filtering duplicate values.
- Create a
Set
fromb
to get the unique values inb
. - Use
Array.prototype.filter()
ona
to only keep values not contained inb
, usingSet.prototype.has()
.
const difference = (a, b) => {
const s = new Set(b);
return a.filter((x) => !s.has(x));
};
difference([1, 2, 3, 3], [1, 2, 4]); // [3, 3]
Returns the difference between two arrays, after applying the provided function to each array element of both.
- Create a
Set
by applyingfn
to each element inb
. - Use
Array.prototype.map()
to applyfn
to each element ina
. - Use
Array.prototype.filter()
in combination withfn
ona
to only keep values not contained inb
, usingSet.prototype.has()
.
const differenceBy = (a, b, fn) => {
const s = new Set(b.map(fn));
return a.map(fn).filter((el) => !s.has(el));
};
differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); // [1]
differenceBy([{ x: 2 }, { x: 1 }], [{ x: 1 }], (v) => v.x); // [2]
Filters out all values from an array for which the comparator function does not return true
.
- Use
Array.prototype.filter()
andArray.prototype.findIndex()
to find the appropriate values. - Omit the last argument,
comp
, to use a default strict equality comparator.
const differenceWith = (arr, val, comp = (a, b) => a === b) =>
arr.filter((a) => val.findIndex((b) => comp(a, b)) === -1);
differenceWith(
[1, 1.2, 1.5, 3, 0],
[1.9, 3, 0],
(a, b) => Math.round(a) === Math.round(b)
); // [1, 1.2]
differenceWith([1, 1.2, 1.3], [1, 1.3, 1.5]); // [1.2]
Gets the target value in a nested JSON object, based on the given key.
- Use the
in
operator to check iftarget
exists inobj
. - If found, return the value of
obj[target]
. - Otherwise use
Object.values(obj)
andArray.prototype.reduce()
to recursively calldig
on each nested object until the first matching key/value pair is found.
const dig = (obj, target) =>
target in obj
? obj[target]
: Object.values(obj).reduce((acc, val) => {
if (acc !== undefined) return acc;
if (typeof val === "object") return dig(val, target);
}, undefined);
const data = {
level1: {
level2: {
level3: "some data",
},
},
};
dig(data, "level3"); // 'some data'
dig(data, "level4"); // undefined
Converts a number to an array of digits, removing its sign if necessary.
- Use
Math.abs()
to strip the number's sign. - Convert the number to a string, using the spread operator (
...
) to build an array. - Use
Array.prototype.map()
andparseInt()
to transform each value to an integer.
const digitize = (n) => [...`${Math.abs(n)}`].map((i) => parseInt(i));
digitize(123); // [1, 2, 3]
digitize(-123); // [1, 2, 3]
Calculates the distance between two points.
- Use
Math.hypot()
to calculate the Euclidean distance between two points.
const distance = (x0, y0, x1, y1) => Math.hypot(x1 - x0, y1 - y0);
distance(1, 1, 2, 3); // ~2.2361
Returns an array consisting of the quotient and remainder of the given numbers.
- Use
Math.floor()
to get the quotient of the divisionx / y
. - Use the modulo operator (
%
) to get the remainder of the divisionx / y
.
const divmod = (x, y) => [Math.floor(x / y), x % y];
divmod(8, 3); // [2, 2]
divmod(3, 8); // [0, 3]
divmod(5, 5); // [1, 0]
Creates a new array with n
elements removed from the left.
- Use
Array.prototype.slice()
to remove the specified number of elements from the left. - Omit the last argument,
n
, to use a default value of1
.
const drop = (arr, n = 1) => arr.slice(n);
drop([1, 2, 3]); // [2, 3]
drop([1, 2, 3], 2); // [3]
drop([1, 2, 3], 42); // []
Creates a new array with n
elements removed from the right.
- Use
Array.prototype.slice()
to remove the specified number of elements from the right. - Omit the last argument,
n
, to use a default value of1
.
const dropRight = (arr, n = 1) => arr.slice(0, -n);
dropRight([1, 2, 3]); // [1, 2]
dropRight([1, 2, 3], 2); // [1]
dropRight([1, 2, 3], 42); // []
Removes elements from the end of an array until the passed function returns true
.
Returns the remaining elements in the array.
- Loop through the array, using
Array.prototype.slice()
to drop the last element of the array until the value returned fromfunc
istrue
. - Return the remaining elements.
const dropRightWhile = (arr, func) => {
let rightIndex = arr.length;
while (rightIndex-- && !func(arr[rightIndex]));
return arr.slice(0, rightIndex + 1);
};
dropRightWhile([1, 2, 3, 4], (n) => n < 3); // [1, 2]
Removes elements in an array until the passed function returns true
.
Returns the remaining elements in the array.
- Loop through the array, using
Array.prototype.slice()
to drop the first element of the array until the value returned fromfunc
istrue
. - Return the remaining elements.
const dropWhile = (arr, func) => {
while (arr.length > 0 && !func(arr[0])) arr = arr.slice(1);
return arr;
};
dropWhile([1, 2, 3, 4], (n) => n >= 3); // [3, 4]
Checks if at least one function returns true
for a given set of arguments.
- Use the logical or (
||
) operator on the result of calling the two functions with the suppliedargs
.
const either =
(f, g) =>
(...args) =>
f(...args) || g(...args);
const isEven = (num) => num % 2 === 0;
const isPositive = (num) => num > 0;
const isPositiveOrEven = either(isPositive, isEven);
isPositiveOrEven(4); // true
isPositiveOrEven(3); // true
Checks if the parent
element contains the child
element.
- Check that
parent
is not the same element aschild
. - Use
Node.contains()
to check if theparent
element contains thechild
element.
const elementContains = (parent, child) =>
parent !== child && parent.contains(child);
elementContains(
document.querySelector("head"),
document.querySelector("title")
);
// true
elementContains(document.querySelector("body"), document.querySelector("body"));
// false
Checks if the given element is focused.
- Use
Document.activeElement
to determine if the given element is focused.
const elementIsFocused = (el) => el === document.activeElement;
elementIsFocused(el); // true if the element is focused
Checks if the element specified is visible in the viewport.
- Use
Element.getBoundingClientRect()
and theWindow.inner(Width|Height)
values to determine if a given element is visible in the viewport. - Omit the second argument to determine if the element is entirely visible, or specify
true
to determine if it is partially visible.
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;
};
// e.g. 100x100 viewport and a 10x10px element at position {top: -1, left: 0, bottom: 9, right: 10}
elementIsVisibleInViewport(el); // false - (not fully visible)
elementIsVisibleInViewport(el, true); // true - (partially visible)
Performs a deep comparison between two values to determine if they are equivalent.
- Check if the two values are identical.
- Check if both values are
Date
objects with the same time, usingDate.prototype.getTime()
. - Check if both values are non-object values with an equivalent value (strict comparison).
- Check if only one value is
null
orundefined
or if their prototypes differ. - If none of the above conditions are met, use
Object.keys()
to check if both values have the same number of keys. - Use
Array.prototype.every()
to check if every key ina
exists inb
and if they are equivalent by callingequals()
recursively.
const equals = (a, b) => {
if (a === b) return true;
if (a instanceof Date && b instanceof Date)
return a.getTime() === b.getTime();
if (!a || !b || (typeof a !== "object" && typeof b !== "object"))
return a === b;
if (a.prototype !== b.prototype) return false;
const keys = Object.keys(a);
if (keys.length !== Object.keys(b).length) return false;
return keys.every((k) => equals(a[k], b[k]));
};
equals(
{ a: [2, { e: 3 }], b: [4], c: "foo" },
{ a: [2, { e: 3 }], b: [4], c: "foo" }
); // true
equals([1, 2, 3], { 0: 1, 1: 2, 2: 3 }); // true
Escapes a string for use in HTML.
- Use
String.prototype.replace()
with a regexp that matches the characters that need to be escaped. - Use the callback function to replace each character instance with its associated escaped character using a dictionary object.
const escapeHTML = (str) =>
str.replace(
/[&<>'"]/g,
(tag) =>
({
"&": "&",
"<": "<",
">": ">",
"'": "'",
'"': """,
}[tag] || tag)
);
escapeHTML('<a href="#">Me & you</a>');
// '<a href="#">Me & you</a>'
Escapes a string to use in a regular expression.
- Use
String.prototype.replace()
to escape special characters.
const escapeRegExp = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
escapeRegExp("(test)"); // \\(test\\)
Calculates the distance between two points in any number of dimensions.
- Use
Object.keys()
andArray.prototype.map()
to map each coordinate to its difference between the two points. - Use
Math.hypot()
to calculate the Euclidean distance between the two points.
const euclideanDistance = (a, b) =>
Math.hypot(...Object.keys(a).map((k) => b[k] - a[k]));
euclideanDistance([1, 1], [2, 3]); // ~2.2361
euclideanDistance([1, 1, 1], [2, 3, 2]); // ~2.4495
Returns every nth
element in an array.
- Use
Array.prototype.filter()
to create a new array that contains everynth
element of a given array.
const everyNth = (arr, nth) => arr.filter((e, i) => i % nth === nth - 1);
everyNth([1, 2, 3, 4, 5, 6], 2); // [ 2, 4, 6 ]
Convert tabs to spaces, where each tab corresponds to count
spaces.
- Use
String.prototype.replace()
with a regular expression andString.prototype.repeat()
to replace each tab character withcount
spaces.
const expandTabs = (str, count) => str.replace(/\t/g, " ".repeat(count));
expandTabs("\t\tlorem", 3); // ' lorem'
Extends a 3-digit color code to a 6-digit color code.
- Use
Array.prototype.map()
,String.prototype.split()
andArray.prototype.join()
to join the mapped array for converting a 3-digit RGB notated hexadecimal color-code to the 6-digit form. Array.prototype.slice()
is used to remove#
from string start since it's added once.
const extendHex = (shortHex) =>
"#" +
shortHex
.slice(shortHex.startsWith("#") ? 1 : 0)
.split("")
.map((x) => x + x)
.join("");
extendHex("#03f"); // '#0033ff'
extendHex("05a"); // '#0055aa'
Calculates the factorial of a number.
- Use recursion.
- If
n
is less than or equal to1
, return1
. - Otherwise, return the product of
n
and the factorial ofn - 1
. - Throw a
TypeError
ifn
is a negative number.
const factorial = (n) =>
n < 0
? (() => {
throw new TypeError("Negative numbers are not allowed!");
})()
: n <= 1
? 1
: n * factorial(n - 1);
factorial(6); // 720
title: fahrenheitToCelsius unlisted: true
Converts Fahrenheit to Celsius.
- Follow the conversion formula
C = (F - 32) * 5/9
.
const fahrenheitToCelsius = (degrees) => ((degrees - 32) * 5) / 9;
fahrenheitToCelsius(32); // 0
Generates an array, containing the Fibonacci sequence, up until the nth term.
- Use
Array.from()
to create an empty array of the specific length, initializing the first two values (0
and1
). - Use
Array.prototype.reduce()
andArray.prototype.concat()
to add values into the array, using the sum of the last two values, except for the first two.
const fibonacci = (n) =>
Array.from({ length: n }).reduce(
(acc, val, i) => acc.concat(i > 1 ? acc[i - 1] + acc[i - 2] : i),
[]
);
fibonacci(6); // [0, 1, 1, 2, 3, 5]
Creates an array with the non-unique values filtered out.
- Use
new Set()
and the spread operator (...
) to create an array of the unique values inarr
. - Use
Array.prototype.filter()
to create an array containing only the unique values.
const filterNonUnique = (arr) =>
[...new Set(arr)].filter((i) => arr.indexOf(i) === arr.lastIndexOf(i));
filterNonUnique([1, 2, 2, 3, 4, 4, 5]); // [1, 3, 5]
Creates an array with the non-unique values filtered out, based on a provided comparator function.
- Use
Array.prototype.filter()
andArray.prototype.every()
to create an array containing only the unique values, based on the comparator function,fn
. - The comparator function takes four arguments: the values of the two elements being compared and their indexes.
const filterNonUniqueBy = (arr, fn) =>
arr.filter((v, i) => arr.every((x, j) => (i === j) === fn(v, x, i, j)));
filterNonUniqueBy(
[
{ id: 0, value: "a" },
{ id: 1, value: "b" },
{ id: 2, value: "c" },
{ id: 1, value: "d" },
{ id: 0, value: "e" },
],
(a, b) => a.id === b.id
); // [ { id: 2, value: 'c' } ]
Creates an array with the unique values filtered out.
- Use
new Set()
and the spread operator (...
) to create an array of the unique values inarr
. - Use
Array.prototype.filter()
to create an array containing only the non-unique values.
const filterUnique = (arr) =>
[...new Set(arr)].filter((i) => arr.indexOf(i) !== arr.lastIndexOf(i));
filterUnique([1, 2, 2, 3, 4, 4, 5]); // [2, 4]
Creates an array with the unique values filtered out, based on a provided comparator function.
- Use
Array.prototype.filter()
andArray.prototype.every()
to create an array containing only the non-unique values, based on the comparator function,fn
. - The comparator function takes four arguments: the values of the two elements being compared and their indexes.
const filterUniqueBy = (arr, fn) =>
arr.filter((v, i) => arr.some((x, j) => (i !== j) === fn(v, x, i, j)));
filterUniqueBy(
[
{ id: 0, value: "a" },
{ id: 1, value: "b" },
{ id: 2, value: "c" },
{ id: 3, value: "d" },
{ id: 0, value: "e" },
],
(a, b) => a.id == b.id
); // [ { id: 0, value: 'a' }, { id: 0, value: 'e' } ]
Finds the anchor node closest to the given node
, if any.
- Use a
for
loop andNode.parentNode
to traverse the node tree upwards from the givennode
. - Use
Node.nodeName
andString.prototype.toLowerCase()
to check if any given node is an anchor ('a'
). - If no matching node is found, return
null
.
const findClosestAnchor = (node) => {
for (let n = node; n.parentNode; n = n.parentNode)
if (n.nodeName.toLowerCase() === "a") return n;
return null;
};
findClosestAnchor(document.querySelector("a > span")); // a
Finds the closest matching node starting at the given node
.
- Use a
for
loop andNode.parentNode
to traverse the node tree upwards from the givennode
. - Use
Element.matches()
to check if any given element node matches the providedselector
. - If no matching node is found, return
null
.
const findClosestMatchingNode = (node, selector) => {
for (let n = node; n.parentNode; n = n.parentNode)
if (n.matches && n.matches(selector)) return n;
return null;
};
findClosestMatchingNode(document.querySelector("span"), "body"); // body
Finds the first n
elements for which the provided function returns a truthy value.
- Use a
for..in
loop to execute the providedmatcher
for each element ofarr
. - Use
Array.prototype.push()
to append elements to the results array and return them if itslength
is equal ton
.
const findFirstN = (arr, matcher, n = 1) => {
let res = [];
for (let i in arr) {
const el = arr[i];
const match = matcher(el, i, arr);
if (match) res.push(el);
if (res.length === n) return res;
}
return res;
};
findFirstN([1, 2, 4, 6], (n) => n % 2 === 0, 2); // [2, 4]
findFirstN([1, 2, 4, 6], (n) => n % 2 === 0, 5); // [2, 4, 6]
Finds the first key that satisfies the provided testing function.
Otherwise undefined
is returned.
- Use
Object.keys(obj)
to get all the properties of the object,Array.prototype.find()
to test each key-value pair usingfn
. - The callback receives three arguments - the value, the key and the object.
const findKey = (obj, fn) =>
Object.keys(obj).find((key) => fn(obj[key], key, obj));
findKey(
{
barney: { age: 36, active: true },
fred: { age: 40, active: false },
pebbles: { age: 1, active: true },
},
(x) => x["active"]
); // 'barney'
Finds all the keys in the provided object that match the given value.
- Use
Object.keys(obj)
to get all the properties of the object. - Use
Array.prototype.filter()
to test each key-value pair and return all keys that are equal to the given value.
const findKeys = (obj, val) =>
Object.keys(obj).filter((key) => obj[key] === val);
const ages = {
Leo: 20,
Zoey: 21,
Jane: 20,
};
findKeys(ages, 20); // [ 'Leo', 'Jane' ]
Finds the last element for which the provided function returns a truthy value.
- Use
Array.prototype.filter()
to remove elements for whichfn
returns falsy values. - Use
Array.prototype.pop()
to get the last element in the filtered array.
const findLast = (arr, fn) => arr.filter(fn).pop();
findLast([1, 2, 3, 4], (n) => n % 2 === 1); // 3
Finds the index of the last element for which the provided function returns a truthy value.
- Use
Array.prototype.map()
to map each element to an array with its index and value. - Use
Array.prototype.filter()
to remove elements for whichfn
returns falsy values - Use
Array.prototype.pop()
to get the last element in the filtered array. - Return
-1
if there are no matching elements.
const findLastIndex = (arr, fn) =>
(arr
.map((val, i) => [i, val])
.filter(([i, val]) => fn(val, i, arr))
.pop() || [-1])[0];
findLastIndex([1, 2, 3, 4], (n) => n % 2 === 1); // 2 (index of the value 3)
findLastIndex([1, 2, 3, 4], (n) => n === 5); // -1 (default value when not found)
Finds the last key that satisfies the provided testing function.
Otherwise undefined
is returned.
- Use
Object.keys(obj)
to get all the properties of the object. - Use
Array.prototype.reverse()
to reverse the order andArray.prototype.find()
to test the provided function for each key-value pair. - The callback receives three arguments - the value, the key and the object.
const findLastKey = (obj, fn) =>
Object.keys(obj)
.reverse()
.find((key) => fn(obj[key], key, obj));
findLastKey(
{
barney: { age: 36, active: true },
fred: { age: 40, active: false },
pebbles: { age: 1, active: true },
},
(x) => x["active"]
); // 'pebbles'
Finds the last n
elements for which the provided function returns a truthy value.
- Use a
for
loop to execute the providedmatcher
for each element ofarr
. - Use
Array.prototype.unshift()
to prepend elements to the results array and return them if itslength
is equal ton
.
const findLastN = (arr, matcher, n = 1) => {
let res = [];
for (let i = arr.length - 1; i >= 0; i--) {
const el = arr[i];
const match = matcher(el, i, arr);
if (match) res.unshift(el);
if (res.length === n) return res;
}
return res;
};
findLastN([1, 2, 4, 6], (n) => n % 2 === 0, 2); // [4, 6]
findLastN([1, 2, 4, 6], (n) => n % 2 === 0, 5); // [2, 4, 6]
Flattens an array up to the specified depth.
- Use recursion, decrementing
depth
by1
for each level of depth. - Use
Array.prototype.reduce()
andArray.prototype.concat()
to merge elements or arrays. - Base case, for
depth
equal to1
stops recursion. - Omit the second argument,
depth
, to flatten only to a depth of1
(single flatten).
const flatten = (arr, depth = 1) =>
arr.reduce(
(a, v) =>
a.concat(depth > 1 && Array.isArray(v) ? flatten(v, depth - 1) : v),
[]
);
flatten([1, [2], 3, 4]); // [1, 2, 3, 4]
flatten([1, [2, [3, [4, 5], 6], 7], 8], 2); // [1, 2, 3, [4, 5], 6, 7, 8]
Flattens an object with the paths for keys.
- Use recursion.
- Use
Object.keys(obj)
combined withArray.prototype.reduce()
to convert every leaf node to a flattened path node. - If the value of a key is an object, the function calls itself with the appropriate
prefix
to create the path usingObject.assign()
. - Otherwise, it adds the appropriate prefixed key-value pair to the accumulator object.
- You should always omit the second argument,
prefix
, unless you want every key to have a prefix.
const flattenObject = (obj, prefix = "") =>
Object.keys(obj).reduce((acc, k) => {
const pre = prefix.length ? `${prefix}.` : "";
if (
typeof obj[k] === "object" &&
obj[k] !== null &&
Object.keys(obj[k]).length > 0
)
Object.assign(acc, flattenObject(obj[k], pre + k));
else acc[pre + k] = obj[k];
return acc;
}, {});
flattenObject({ a: { b: { c: 1 } }, d: 1 }); // { 'a.b.c': 1, d: 1 }
Takes a function as an argument, then makes the first argument the last.
- Use argument destructuring and a closure with variadic arguments.
- Splice the first argument, using the spread operator (
...
), to make it the last before applying the rest.
const flip =
(fn) =>
(first, ...rest) =>
fn(...rest, first);
let a = { name: "John Smith" };
let b = {};
const mergeFrom = flip(Object.assign);
let mergePerson = mergeFrom.bind(null, a);
mergePerson(b); // == b
b = {};
Object.assign(b, a); // == b
Executes a provided function once for each array element, starting from the array's last element.
- Use
Array.prototype.slice()
to clone the given array andArray.prototype.reverse()
to reverse it. - Use
Array.prototype.forEach()
to iterate over the reversed array.
const forEachRight = (arr, callback) => arr.slice().reverse().forEach(callback);
forEachRight([1, 2, 3, 4], (val) => console.log(val)); // '4', '3', '2', '1'
Iterates over all own properties of an object, running a callback for each one.
- Use
Object.keys(obj)
to get all the properties of the object. - Use
Array.prototype.forEach()
to run the provided function for each key-value pair. - The callback receives three arguments - the value, the key and the object.
const forOwn = (obj, fn) =>
Object.keys(obj).forEach((key) => fn(obj[key], key, obj));
forOwn({ foo: "bar", a: 1 }, (v) => console.log(v)); // 'bar', 1
Iterates over all own properties of an object in reverse, running a callback for each one.
- Use
Object.keys(obj)
to get all the properties of the object,Array.prototype.reverse()
to reverse their order. - Use
Array.prototype.forEach()
to run the provided function for each key-value pair. - The callback receives three arguments - the value, the key and the object.
const forOwnRight = (obj, fn) =>
Object.keys(obj)
.reverse()
.forEach((key) => fn(obj[key], key, obj));
forOwnRight({ foo: "bar", a: 1 }, (v) => console.log(v)); // 1, 'bar'
Encodes a set of form elements as an object
.
- Use the
FormData
constructor to convert the HTMLform
toFormData
andArray.from()
to convert to an array. - Collect the object from the array using
Array.prototype.reduce()
.
const formToObject = (form) =>
Array.from(new FormData(form)).reduce(
(acc, [key, value]) => ({
...acc,
[key]: value,
}),
{}
);
formToObject(document.querySelector("#form"));
// { email: 'test@email.com', name: 'Test Name' }
Returns the human-readable format of the given number of milliseconds.
- Divide
ms
with the appropriate values to obtain the appropriate values forday
,hour
,minute
,second
andmillisecond
. - Use
Object.entries()
withArray.prototype.filter()
to keep only non-zero values. - Use
Array.prototype.map()
to create the string for each value, pluralizing appropriately. - Use
String.prototype.join(', ')
to combine the values into a string.
const formatDuration = (ms) => {
if (ms < 0) ms = -ms;
const time = {
day: Math.floor(ms / 86400000),
hour: Math.floor(ms / 3600000) % 24,
minute: Math.floor(ms / 60000) % 60,
second: Math.floor(ms / 1000) % 60,
millisecond: Math.floor(ms) % 1000,
};
return Object.entries(time)
.filter((val) => val[1] !== 0)
.map(([key, val]) => `${val} ${key}${val !== 1 ? "s" : ""}`)
.join(", ");
};
formatDuration(1001); // '1 second, 1 millisecond'
formatDuration(34325055574);
// '397 days, 6 hours, 44 minutes, 15 seconds, 574 milliseconds'
Formats a number using the local number format order.
- Use
Number.prototype.toLocaleString()
to convert a number to using the local number format separators.
const formatNumber = (num) => num.toLocaleString();
formatNumber(123456); // '123,456' in `en-US`
formatNumber(15675436903); // '15.675.436.903' in `de-DE`
Returns the ISO format of the given number of seconds.
- Divide
s
with the appropriate values to obtain the appropriate values forhour
,minute
andsecond
. - Store the
sign
in a variable to prepend it to the result. - Use
Array.prototype.map()
in combination withMath.floor()
andString.prototype.padStart()
to stringify and format each segment. - Use
String.prototype.join(':')
to combine the values into a string.
const formatSeconds = (s) => {
const [hour, minute, second, sign] =
s > 0
? [s / 3600, (s / 60) % 60, s % 60, ""]
: [-s / 3600, (-s / 60) % 60, -s % 60, "-"];
return (
sign +
[hour, minute, second]
.map((v) => `${Math.floor(v)}`.padStart(2, "0"))
.join(":")
);
};
formatSeconds(200); // '00:03:20'
formatSeconds(-200); // '-00:03:20'
formatSeconds(99999); // '27:46:39'
Creates an object with the unique values of an array as keys and their frequencies as the values.
- Use
Array.prototype.reduce()
to map unique values to an object's keys, adding to existing keys every time the same value is encountered.
const frequencies = (arr) =>
arr.reduce((a, v) => {
a[v] = a[v] ? a[v] + 1 : 1;
return a;
}, {});
frequencies(["a", "b", "a", "c", "a", "a", "b"]); // { a: 4, b: 2, c: 1 }
frequencies([..."ball"]); // { b: 1, a: 1, l: 2 }
Converts a string from camelcase.
- Use
String.prototype.replace()
to break the string into words and add aseparator
between them. - Omit the second argument to use a default
separator
of_
.
const fromCamelCase = (str, separator = "_") =>
str
.replace(/([a-z\d])([A-Z])/g, "$1" + separator + "$2")
.replace(/([A-Z]+)([A-Z][a-z\d]+)/g, "$1" + separator + "$2")
.toLowerCase();
fromCamelCase("someDatabaseFieldName", " "); // 'some database field name'
fromCamelCase("someLabelThatNeedsToBeDecamelized", "-");
// 'some-label-that-needs-to-be-decamelized'
fromCamelCase("someJavascriptProperty", "_"); // 'some_javascript_property'
fromCamelCase("JSONToCSV", "."); // 'json.to.csv'
Creates a Date
object from a Unix timestamp.
- Convert the timestamp to milliseconds by multiplying with
1000
. - Use
new Date()
to create a newDate
object.
const fromTimestamp = (timestamp) => new Date(timestamp * 1000);
fromTimestamp(1602162242); // 2020-10-08T13:04:02.000Z
Creates a frozen Set
object.
- Use the
new Set()
constructor to create a newSet
object fromiterable
. - Set the
add
,delete
andclear
methods of the newly created object toundefined
, so that they cannot be used, practically freezing the object.
const frozenSet = (iterable) => {
const s = new Set(iterable);
s.add = undefined;
s.delete = undefined;
s.clear = undefined;
return s;
};
frozenSet([1, 2, 3, 1, 2]);
// Set { 1, 2, 3, add: undefined, delete: undefined, clear: undefined }
Opens or closes an element in fullscreen mode.
- Use
Document.querySelector()
andElement.requestFullscreen()
to open the given element in fullscreen. - Use
Document.exitFullscreen()
to exit fullscreen mode. - Omit the second argument,
el
, to usebody
as the default element. - Omit the first element,
mode
, to open the element in fullscreen mode by default.
const fullscreen = (mode = true, el = "body") =>
mode
? document.querySelector(el).requestFullscreen()
: document.exitFullscreen();
fullscreen(); // Opens `body` in fullscreen mode
fullscreen(false); // Exits fullscreen mode
Logs the name of a function.
- Use
console.debug()
and thename
property of the passed function to log the function's name to thedebug
channel of the console. - Return the given function
fn
.
const functionName = (fn) => (console.debug(fn.name), fn);
let m = functionName(Math.max)(5, 6);
// max (logged in debug channel of console)
// m = 6
Gets an array of function property names from own (and optionally inherited) enumerable properties of an object.
- Use
Object.keys(obj)
to iterate over the object's own properties. - If
inherited
istrue
, useObject.getPrototypeOf(obj)
to also get the object's inherited properties. - Use
Array.prototype.filter()
to keep only those properties that are functions. - Omit the second argument,
inherited
, to not include inherited properties by default.
const functions = (obj, inherited = false) =>
(inherited
? [...Object.keys(obj), ...Object.keys(Object.getPrototypeOf(obj))]
: Object.keys(obj)
).filter((key) => typeof obj[key] === "function");
function Foo() {
this.a = () => 1;
this.b = () => 2;
}
Foo.prototype.c = () => 3;
functions(new Foo()); // ['a', 'b']
functions(new Foo(), true); // ['a', 'b', 'c']
Calculates the greatest common divisor between two or more numbers/arrays.
- The inner
_gcd
function uses recursion. - Base case is when
y
equals0
. In this case, returnx
. - Otherwise, return the GCD of
y
and the remainder of the divisionx/y
.
const gcd = (...arr) => {
const _gcd = (x, y) => (!y ? x : gcd(y, x % y));
return [...arr].reduce((a, b) => _gcd(a, b));
};
gcd(8, 36); // 4
gcd(...[12, 8, 32]); // 4
Generates an array with the given amount of items, using the given function.
- Use
Array.from()
to create an empty array of the specific length, callingfn
with the index of each newly created element. - The callback takes one argument - the index of each element.
const generateItems = (n, fn) => Array.from({ length: n }, (_, i) => fn(i));
generateItems(10, Math.random);
// [0.21, 0.08, 0.40, 0.96, 0.96, 0.24, 0.19, 0.96, 0.42, 0.70]
Converts the output of a generator function to an array.
- Use the spread operator (
...
) to convert the output of the generator function to an array.
const generatorToArray = (gen) => [...gen];
const s = new Set([1, 2, 1, 3, 1, 4]);
generatorToArray(s.entries()); // [[ 1, 1 ], [ 2, 2 ], [ 3, 3 ], [ 4, 4 ]]
Initializes an array containing the numbers in the specified range where start
and end
are inclusive and the ratio between two terms is step
.
Returns an error if step
equals 1
.
- Use
Array.from()
,Math.log()
andMath.floor()
to create an array of the desired length,Array.prototype.map()
to fill with the desired values in a range. - Omit the second argument,
start
, to use a default value of1
. - Omit the third argument,
step
, to use a default value of2
.
const geometricProgression = (end, start = 1, step = 2) =>
Array.from({
length: Math.floor(Math.log(end / start) / Math.log(step)) + 1,
}).map((_, i) => start * step ** i);
geometricProgression(256); // [1, 2, 4, 8, 16, 32, 64, 128, 256]
geometricProgression(256, 3); // [3, 6, 12, 24, 48, 96, 192]
geometricProgression(256, 1, 4); // [1, 4, 16, 64, 256]
Retrieves a set of properties indicated by the given selectors from an object.
- Use
Array.prototype.map()
for each selector,String.prototype.replace()
to replace square brackets with dots. - Use
String.prototype.split('.')
to split each selector. - Use
Array.prototype.filter()
to remove empty values andArray.prototype.reduce()
to get the value indicated by each selector.
const get = (from, ...selectors) =>
[...selectors].map((s) =>
s
.replace(/\[([^\[\]]*)\]/g, ".$1.")
.split(".")
.filter((t) => t !== "")
.reduce((prev, cur) => prev && prev[cur], from)
);
const obj = {
selector: { to: { val: "val to select" } },
target: [1, 2, { a: "test" }],
};
get(obj, "selector.to.val", "target[0]", "target[2].a");
// ['val to select', 1, 'test']
Returns all the ancestors of an element from the document root to the given element.
- Use
Node.parentNode
and awhile
loop to move up the ancestor tree of the element. - Use
Array.prototype.unshift()
to add each new ancestor to the start of the array.
const getAncestors = (el) => {
let ancestors = [];
while (el) {
ancestors.unshift(el);
el = el.parentNode;
}
return ancestors;
};
getAncestors(document.querySelector("nav"));
// [document, html, body, header, nav]
Gets the current URL without any parameters or fragment identifiers.
- Use
String.prototype.replace()
with an appropriate regular expression to remove everything after either'?'
or'#'
, if found.
const getBaseURL = (url) => url.replace(/[?#].*$/, "");
getBaseURL("http://url.com/page?name=Adam&surname=Smith");
// 'http://url.com/page'
Returns a string of the form HH:MM:SS
from a Date
object.
- Use
Date.prototype.toTimeString()
andString.prototype.slice()
to get theHH:MM:SS
part of a givenDate
object.
const getColonTimeFromDate = (date) => date.toTimeString().slice(0, 8);
getColonTimeFromDate(new Date()); // '08:38:00'
Calculates the difference (in days) between two dates.
- Subtract the two
Date
objects and divide by the number of milliseconds in a day to get the difference (in days) between them.
const getDaysDiffBetweenDates = (dateInitial, dateFinal) =>
(dateFinal - dateInitial) / (1000 * 3600 * 24);
getDaysDiffBetweenDates(new Date("2017-12-13"), new Date("2017-12-22")); // 9
Returns an array of HTML elements whose width is larger than that of the viewport's.
- Use
HTMLElement.offsetWidth
to get the width of thedocument
. - Use
Array.prototype.filter()
on the result ofDocument.querySelectorAll()
to check the width of all elements in the document.
const getElementsBiggerThanViewport = () => {
const docWidth = document.documentElement.offsetWidth;
return [...document.querySelectorAll("*")].filter(
(el) => el.offsetWidth > docWidth
);
};
getElementsBiggerThanViewport(); // <div id="ultra-wide-item" />
Calculates the difference (in hours) between two dates.
- Subtract the two
Date
objects and divide by the number of milliseconds in an hour to get the difference (in hours) between them.
const getHoursDiffBetweenDates = (dateInitial, dateFinal) =>
(dateFinal - dateInitial) / (1000 * 3600);
getHoursDiffBetweenDates(
new Date("2021-04-24 10:25:00"),
new Date("2021-04-25 10:25:00")
); // 24
Fetches all images from within an element and puts them into an array.
- Use
Element.getElementsByTagName()
to get all<img>
elements inside the provided element. - Use
Array.prototype.map()
to map everysrc
attribute of each<img>
element. - If
includeDuplicates
isfalse
, create a newSet
to eliminate duplicates and return it after spreading into an array. - Omit the second argument,
includeDuplicates
, to discard duplicates by default.
const getImages = (el, includeDuplicates = false) => {
const images = [...el.getElementsByTagName("img")].map((img) =>
img.getAttribute("src")
);
return includeDuplicates ? images : [...new Set(images)];
};
getImages(document, true); // ['image1.jpg', 'image2.png', 'image1.png', '...']
getImages(document, false); // ['image1.jpg', 'image2.png', '...']
Converts an integer to a suffixed string, adding am
or pm
based on its value.
- Use the modulo operator (
%
) and conditional checks to transform an integer to a stringified 12-hour format with meridiem suffix.
const getMeridiemSuffixOfInteger = (num) =>
num === 0 || num === 24
? 12 + "am"
: num === 12
? 12 + "pm"
: num < 12
? (num % 12) + "am"
: (num % 12) + "pm";
getMeridiemSuffixOfInteger(0); // '12am'
getMeridiemSuffixOfInteger(11); // '11am'
getMeridiemSuffixOfInteger(13); // '1pm'
getMeridiemSuffixOfInteger(25); // '1pm'
Calculates the difference (in minutes) between two dates.
- Subtract the two
Date
objects and divide by the number of milliseconds in a minute to get the difference (in minutes) between them.
const getMinutesDiffBetweenDates = (dateInitial, dateFinal) =>
(dateFinal - dateInitial) / (1000 * 60);
getMinutesDiffBetweenDates(
new Date("2021-04-24 01:00:15"),
new Date("2021-04-24 02:00:15")
); // 60
Calculates the difference (in months) between two dates.
- Use
Date.prototype.getFullYear()
andDate.prototype.getMonth()
to calculate the difference (in months) between twoDate
objects.
const getMonthsDiffBetweenDates = (dateInitial, dateFinal) =>
Math.max(
(dateFinal.getFullYear() - dateInitial.getFullYear()) * 12 +
dateFinal.getMonth() -
dateInitial.getMonth(),
0
);
getMonthsDiffBetweenDates(new Date("2017-12-13"), new Date("2018-04-29")); // 4
Finds all the ancestors of an element up until the element matched by the specified selector.
- Use
Node.parentNode
and awhile
loop to move up the ancestor tree of the element. - Use
Array.prototype.unshift()
to add each new ancestor to the start of the array. - Use
Element.matches()
to check if the current element matches the specifiedselector
.
const getParentsUntil = (el, selector) => {
let parents = [],
_el = el.parentNode;
while (_el && typeof _el.matches === "function") {
parents.unshift(_el);
if (_el.matches(selector)) return parents;
else _el = _el.parentNode;
}
return [];
};
getParentsUntil(document.querySelector("#home-link"), "header");
// [header, nav, ul, li]
Gets the protocol being used on the current page.
- Use
Window.location.protocol
to get the protocol (http:
orhttps:
) of the current page.
const getProtocol = () => window.location.protocol;
getProtocol(); // 'https:'
Returns the scroll position of the current page.
- Use
Window.pageXOffset
andWindow.pageYOffset
if they are defined, otherwiseElement.scrollLeft
andElement.scrollTop
. - Omit the single argument,
el
, to use a default value ofwindow
.
const getScrollPosition = (el = window) => ({
x: el.pageXOffset !== undefined ? el.pageXOffset : el.scrollLeft,
y: el.pageYOffset !== undefined ? el.pageYOffset : el.scrollTop,
});
getScrollPosition(); // {x: 0, y: 200}
Calculates the difference (in seconds) between two dates.
- Subtract the two
Date
objects and divide by the number of milliseconds in a second to get the difference (in seconds) between them.
const getSecondsDiffBetweenDates = (dateInitial, dateFinal) =>
(dateFinal - dateInitial) / 1000;
getSecondsDiffBetweenDates(
new Date("2020-12-24 00:00:15"),
new Date("2020-12-24 00:00:17")
); // 2
Gets the currently selected text.
- Use
Window.getSelection()
andSelection.toString()
to get the currently selected text.
const getSelectedText = () => window.getSelection().toString();
getSelectedText(); // 'Lorem ipsum'
Returns an array containing all the siblings of the given element.
- Use
Node.parentNode
andNode.childNodes
to get aNodeList
of all the elements contained in the element's parent. - Use the spread operator (
...
) andArray.prototype.filter()
to convert to an array and remove the given element from it.
const getSiblings = (el) =>
[...el.parentNode.childNodes].filter((node) => node !== el);
getSiblings(document.querySelector("head")); // ['body']
Retrieves the value of a CSS rule for the specified element.
- Use
Window.getComputedStyle()
to get the value of the CSS rule for the specified element.
const getStyle = (el, ruleName) => getComputedStyle(el)[ruleName];
getStyle(document.querySelector("p"), "font-size"); // '16px'
Gets the Unix timestamp from a Date
object.
- Use
Date.prototype.getTime()
to get the timestamp in milliseconds and divide by1000
to get the timestamp in seconds. - Use
Math.floor()
to appropriately round the resulting timestamp to an integer. - Omit the argument,
date
, to use the current date.
const getTimestamp = (date = new Date()) => Math.floor(date.getTime() / 1000);
getTimestamp(); // 1602162242
Returns the native type of a value.
- Return
'undefined'
or'null'
if the value isundefined
ornull
. - Otherwise, use
Object.prototype.constructor.name
to get the name of the constructor.
const getType = (v) =>
v === undefined ? "undefined" : v === null ? "null" : v.constructor.name;
getType(new Set([1, 2, 3])); // 'Set'
Creates an object containing the parameters of the current URL.
- Use
String.prototype.match()
with an appropriate regular expression to get all key-value pairs. - Use
Array.prototype.reduce()
to map and combine them into a single object. - Pass
location.search
as the argument to apply to the currenturl
.
const getURLParameters = (url) =>
(url.match(/([^?=&]+)(=([^&]*))/g) || []).reduce(
(a, v) => (
(a[v.slice(0, v.indexOf("="))] = v.slice(v.indexOf("=") + 1)), a
),
{}
);
getURLParameters("google.com"); // {}
getURLParameters("http://url.com/page?name=Adam&surname=Smith");
// {name: 'Adam', surname: 'Smith'}
Finds the distance from a given element to the top of the document.
- Use a
while
loop andHTMLElement.offsetParent
to move up the offset parents of the given element. - Add
HTMLElement.offsetTop
for each element and return the result.
const getVerticalOffset = (el) => {
let offset = el.offsetTop,
_el = el;
while (_el.offsetParent) {
_el = _el.offsetParent;
offset += _el.offsetTop;
}
return offset;
};
getVerticalOffset(".my-element"); // 120
Groups the elements of an array based on the given function.
- Use
Array.prototype.map()
to map the values of the array to a function or property name. - Use
Array.prototype.reduce()
to create an object, where the keys are produced from the mapped results.
const groupBy = (arr, fn) =>
arr
.map(typeof fn === "function" ? fn : (val) => val[fn])
.reduce((acc, val, i) => {
acc[val] = (acc[val] || []).concat(arr[i]);
return acc;
}, {});
groupBy([6.1, 4.2, 6.3], Math.floor); // {4: [4.2], 6: [6.1, 6.3]}
groupBy(["one", "two", "three"], "length"); // {3: ['one', 'two'], 5: ['three']}
Calculates the Hamming distance between two values.
- Use the XOR operator (
^
) to find the bit difference between the two numbers. - Convert to a binary string using
Number.prototype.toString(2)
. - Count and return the number of
1
s in the string, usingString.prototype.match(/1/g)
.
const hammingDistance = (num1, num2) =>
((num1 ^ num2).toString(2).match(/1/g) || "").length;
hammingDistance(2, 3); // 1
Checks if the given element has the specified class.
- Use
Element.classList
andDOMTokenList.contains()
to check if the element has the specified class.
const hasClass = (el, className) => el.classList.contains(className);
hasClass(document.querySelector("p.special"), "special"); // true
Checks if there are duplicate values in a flat array.
- Use
Set()
to get the unique values in the array. - Use
Set.prototype.size
andArray.prototype.length
to check if the count of the unique values is the same as elements in the original array.
const hasDuplicates = (arr) => new Set(arr).size !== arr.length;
hasDuplicates([0, 1, 1, 2]); // true
hasDuplicates([0, 1, 2, 3]); // false
Checks if the current process's arguments contain the specified flags.
- Use
Array.prototype.every()
andArray.prototype.includes()
to check ifprocess.argv
contains all the specified flags. - Use a regular expression to test if the specified flags are prefixed with
-
or--
and prefix them accordingly.
const hasFlags = (...flags) =>
flags.every((flag) =>
process.argv.includes(/^-{1,2}/.test(flag) ? flag : "--" + flag)
);
// node myScript.js -s --test --cool=true
hasFlags("-s"); // true
hasFlags("--test", "cool=true", "-s"); // true
hasFlags("special"); // false
Checks if the target value exists in a JSON object.
- Check if
keys
is non-empty and useArray.prototype.every()
to sequentially check its keys to internal depth of the object,obj
. - Use
Object.prototype.hasOwnProperty()
to check ifobj
does not have the current key or is not an object, stop propagation and returnfalse
. - Otherwise assign the key's value to
obj
to use on the next iteration. - Return
false
beforehand if given key list is empty.
const hasKey = (obj, keys) => {
return (
keys.length > 0 &&
keys.every((key) => {
if (typeof obj !== "object" || !obj.hasOwnProperty(key)) return false;
obj = obj[key];
return true;
})
);
};
let obj = {
a: 1,
b: { c: 4 },
"b.d": 5,
};
hasKey(obj, ["a"]); // true
hasKey(obj, ["b"]); // true
hasKey(obj, ["b", "c"]); // true
hasKey(obj, ["b.d"]); // true
hasKey(obj, ["d"]); // false
hasKey(obj, ["c"]); // false
hasKey(obj, ["b", "f"]); // false
Checks if an array has more than one value matching the given function.
- Use
Array.prototype.filter()
in combination withfn
to find all matching array elements. - Use
Array.prototype.length
to check if more than one element matchfn
.
const hasMany = (arr, fn) => arr.filter(fn).length > 1;
hasMany([1, 3], (x) => x % 2); // true
hasMany([1, 2], (x) => x % 2); // false
Checks if an array has only one value matching the given function.
- Use
Array.prototype.filter()
in combination withfn
to find all matching array elements. - Use
Array.prototype.length
to check if only one element matchesfn
.
const hasOne = (arr, fn) => arr.filter(fn).length === 1;
hasOne([1, 2], (x) => x % 2); // true
hasOne([1, 3], (x) => x % 2); // false
Creates a hash for a value using the SHA-256 algorithm. Returns a promise.
- Use the SubtleCrypto API to create a hash for the given value.
- Create a new
TextEncoder
and use it to encodeval
. Pass its value toSubtleCrypto.digest()
to generate a digest of the given data. - Use
DataView.prototype.getUint32()
to read data from the resolvedArrayBuffer
. - Convert the data to it hexadecimal representation using
Number.prototype.toString(16)
. Add the data to an array usingArray.prototype.push()
. - Finally, use
Array.prototype.join()
to combine values in the array ofhexes
into a string.
const hashBrowser = (val) =>
crypto.subtle
.digest("SHA-256", new TextEncoder("utf-8").encode(val))
.then((h) => {
let hexes = [],
view = new DataView(h);
for (let i = 0; i < view.byteLength; i += 4)
hexes.push(("00000000" + view.getUint32(i).toString(16)).slice(-8));
return hexes.join("");
});
hashBrowser(
JSON.stringify({ a: "a", b: [1, 2, 3, 4], foo: { c: "bar" } })
).then(console.log);
// '04aa106279f5977f59f9067fa9712afc4aedc6f5862a8defc34552d8c7206393'
Creates a hash for a value using the SHA-256 algorithm. Returns a promise.
- Use
crypto.createHash()
to create aHash
object with the appropriate algorithm. - Use
hash.update()
to add the data fromval
to theHash
,hash.digest()
to calculate the digest of the data. - Use
setTimeout()
to prevent blocking on a long operation. Return aPromise
to give it a familiar interface.
const crypto = require("crypto");
const hashNode = (val) =>
new Promise((resolve) =>
setTimeout(
() => resolve(crypto.createHash("sha256").update(val).digest("hex")),
0
)
);
hashNode(JSON.stringify({ a: "a", b: [1, 2, 3, 4], foo: { c: "bar" } })).then(
console.log
);
// '04aa106279f5977f59f9067fa9712afc4aedc6f5862a8defc34552d8c7206393'
Checks if two arrays contain the same elements regardless of order.
- Use a
for...of
loop over aSet
created from the values of both arrays. - Use
Array.prototype.filter()
to compare the amount of occurrences of each distinct value in both arrays. - Return
false
if the counts do not match for any element,true
otherwise.
const haveSameContents = (a, b) => {
for (const v of new Set([...a, ...b]))
if (a.filter((e) => e === v).length !== b.filter((e) => e === v).length)
return false;
return true;
};
haveSameContents([1, 2, 4], [2, 4, 1]); // true
Returns the head of an array.
- Check if
arr
is truthy and has alength
property. - Use
arr[0]
if possible to return the first element, otherwise returnundefined
.
const head = (arr) => (arr && arr.length ? arr[0] : undefined);
head([1, 2, 3]); // 1
head([]); // undefined
head(null); // undefined
head(undefined); // undefined
Sorts an array of numbers, using the heapsort algorithm.
- Use recursion.
- Use the spread operator (
...
) to clone the original array,arr
. - Use closures to declare a variable,
l
, and a functionheapify
. - Use a
for
loop andMath.floor()
in combination withheapify
to create a max heap from the array. - Use a
for
loop to repeatedly narrow down the considered range, usingheapify
and swapping values as necessary in order to sort the cloned array.
const heapsort = (arr) => {
const a = [...arr];
let l = a.length;
const heapify = (a, i) => {
const left = 2 * i + 1;
const right = 2 * i + 2;
let max = i;
if (left < l && a[left] > a[max]) max = left;
if (right < l && a[right] > a[max]) max = right;
if (max !== i) {
[a[max], a[i]] = [a[i], a[max]];
heapify(a, max);
}
};
for (let i = Math.floor(l / 2); i >= 0; i -= 1) heapify(a, i);
for (i = a.length - 1; i > 0; i--) {
[a[0], a[i]] = [a[i], a[0]];
l--;
heapify(a, 0);
}
return a;
};
heapsort([6, 3, 4, 1]); // [1, 3, 4, 6]
Converts a color code to an rgb()
or rgba()
string if alpha value is provided.
- Use bitwise right-shift operator and mask bits with
&
(and) operator to convert a hexadecimal color code (with or without prefixed with#
) to a string with the RGB values. - If it's 3-digit color code, first convert to 6-digit version.
- If an alpha value is provided alongside 6-digit hex, give
rgba()
string in return.
const hexToRGB = (hex) => {
let alpha = false,
h = hex.slice(hex.startsWith("#") ? 1 : 0);
if (h.length === 3) h = [...h].map((x) => x + x).join("");
else if (h.length === 8) alpha = true;
h = parseInt(h, 16);
return (
"rgb" +
(alpha ? "a" : "") +
"(" +
(h >>> (alpha ? 24 : 16)) +
", " +
((h & (alpha ? 0x00ff0000 : 0x00ff00)) >>> (alpha ? 16 : 8)) +
", " +
((h & (alpha ? 0x0000ff00 : 0x0000ff)) >>> (alpha ? 8 : 0)) +
(alpha ? `, ${h & 0x000000ff}` : "") +
")"
);
};
hexToRGB("#27ae60ff"); // 'rgba(39, 174, 96, 255)'
hexToRGB("27ae60"); // 'rgb(39, 174, 96)'
hexToRGB("#fff"); // 'rgb(255, 255, 255)'
Hides all the elements specified.
- Use the spread operator (
...
) andArray.prototype.forEach()
to applydisplay: none
to each element specified.
const hide = (...el) => [...el].forEach((e) => (e.style.display = "none"));
hide(...document.querySelectorAll("img")); // Hides all <img> elements on the page
Makes a DELETE
request to the passed URL.
- Use the
XMLHttpRequest
web API to make aDELETE
request to the givenurl
. - Handle the
onload
event, by running the providedcallback
function. - Handle the
onerror
event, by running the providederr
function. - Omit the third argument,
err
to log the request to the console's error stream by default.
const httpDelete = (url, callback, err = console.error) => {
const request = new XMLHttpRequest();
request.open("DELETE", url, true);
request.onload = () => callback(request);
request.onerror = () => err(request);
request.send();
};
httpDelete("https://jsonplaceholder.typicode.com/posts/1", (request) => {
console.log(request.responseText);
}); // Logs: {}
Makes a GET
request to the passed URL.
- Use the
XMLHttpRequest
web API to make aGET
request to the givenurl
. - Handle the
onload
event, by calling the givencallback
theresponseText
. - Handle the
onerror
event, by running the providederr
function. - Omit the third argument,
err
, to log errors to the console'serror
stream by default.
const httpGet = (url, callback, err = console.error) => {
const request = new XMLHttpRequest();
request.open("GET", url, true);
request.onload = () => callback(request.responseText);
request.onerror = () => err(request);
request.send();
};
httpGet("https://jsonplaceholder.typicode.com/posts/1", console.log); /*
Logs: {
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}
*/
Makes a POST
request to the passed URL.
- Use the
XMLHttpRequest
web API to make aPOST
request to the givenurl
. - Set the value of an
HTTP
request header withsetRequestHeader
method. - Handle the
onload
event, by calling the givencallback
theresponseText
. - Handle the
onerror
event, by running the providederr
function. - Omit the fourth argument,
err
, to log errors to the console'serror
stream by default.
const httpPost = (url, data, callback, err = console.error) => {
const request = new XMLHttpRequest();
request.open("POST", url, true);
request.setRequestHeader("Content-type", "application/json; charset=utf-8");
request.onload = () => callback(request.responseText);
request.onerror = () => err(request);
request.send(data);
};
const newPost = {
userId: 1,
id: 1337,
title: "Foo",
body: "bar bar bar",
};
const data = JSON.stringify(newPost);
httpPost("https://jsonplaceholder.typicode.com/posts", data, console.log); /*
Logs: {
"userId": 1,
"id": 1337,
"title": "Foo",
"body": "bar bar bar"
}
*/
httpPost(
"https://jsonplaceholder.typicode.com/posts",
null, // does not send a body
console.log
); /*
Logs: {
"id": 101
}
*/
Makes a PUT
request to the passed URL.
- Use
XMLHttpRequest
web api to make aPUT
request to the givenurl
. - Set the value of an
HTTP
request header withsetRequestHeader
method. - Handle the
onload
event, by running the providedcallback
function. - Handle the
onerror
event, by running the providederr
function. - Omit the last argument,
err
to log the request to the console's error stream by default.
const httpPut = (url, data, callback, err = console.error) => {
const request = new XMLHttpRequest();
request.open("PUT", url, true);
request.setRequestHeader("Content-type", "application/json; charset=utf-8");
request.onload = () => callback(request);
request.onerror = () => err(request);
request.send(data);
};
const password = "fooBaz";
const data = JSON.stringify({
id: 1,
title: "foo",
body: "bar",
userId: 1,
});
httpPut("https://jsonplaceholder.typicode.com/posts/1", data, (request) => {
console.log(request.responseText);
}); /*
Logs: {
id: 1,
title: 'foo',
body: 'bar',
userId: 1
}
*/
Redirects the page to HTTPS if it's currently in HTTP.
- Use
location.protocol
to get the protocol currently being used. - If it's not HTTPS, use
location.replace()
to replace the existing page with the HTTPS version of the page. - Use
location.href
to get the full address, split it withString.prototype.split()
and remove the protocol part of the URL. - Note that pressing the back button doesn't take it back to the HTTP page as its replaced in the history.
const httpsRedirect = () => {
if (location.protocol !== "https:")
location.replace("https://" + location.href.split("//")[1]);
};
httpsRedirect();
// If you are on http://mydomain.com, you are redirected to https://mydomain.com
title: hz unlisted: true
Measures the number of times a function is executed per second (hz
/hertz
).
- Use
performance.now()
to get the difference in milliseconds before and after the iteration loop to calculate the time elapsed executing the functioniterations
times. - Return the number of cycles per second by converting milliseconds to seconds and dividing it by the time elapsed.
- Omit the second argument,
iterations
, to use the default of 100 iterations.
const hz = (fn, iterations = 100) => {
const before = performance.now();
for (let i = 0; i < iterations; i++) fn();
return (1000 * iterations) / (performance.now() - before);
};
const numbers = Array(10000)
.fill()
.map((_, i) => i);
const sumReduce = () => numbers.reduce((acc, n) => acc + n, 0);
const sumForLoop = () => {
let sum = 0;
for (let i = 0; i < numbers.length; i++) sum += numbers[i];
return sum;
};
Math.round(hz(sumReduce)); // 572
Math.round(hz(sumForLoop)); // 4784
Checks if the given number falls within the given range.
- Use arithmetic comparison to check if the given number is in the specified range.
- If the second argument,
end
, is not specified, the range is considered to be from0
tostart
.
const inRange = (n, start, end = null) => {
if (end && start > end) [end, start] = [start, end];
return end == null ? n >= 0 && n < start : n >= start && n < end;
};
inRange(3, 2, 5); // true
inRange(3, 4); // true
inRange(2, 3, 5); // false
inRange(3, 2); // false
Checks if all the elements in values
are included in arr
.
- Use
Array.prototype.every()
andArray.prototype.includes()
to check if all elements ofvalues
are included inarr
.
const includesAll = (arr, values) => values.every((v) => arr.includes(v));
includesAll([1, 2, 3, 4], [1, 4]); // true
includesAll([1, 2, 3, 4], [1, 5]); // false
Checks if at least one element of values
is included in arr
.
- Use
Array.prototype.some()
andArray.prototype.includes()
to check if at least one element ofvalues
is included inarr
.
const includesAny = (arr, values) => values.some((v) => arr.includes(v));
includesAny([1, 2, 3, 4], [2, 9]); // true
includesAny([1, 2, 3, 4], [8, 9]); // false
Indents each line in the provided string.
- Use
String.prototype.replace()
and a regular expression to add the character specified byindent
count
times at the start of each line. - Omit the third argument,
indent
, to use a default indentation character of' '
.
const indentString = (str, count, indent = " ") =>
str.replace(/^/gm, indent.repeat(count));
indentString("Lorem\nIpsum", 2); // ' Lorem\n Ipsum'
indentString("Lorem\nIpsum", 2, "_"); // '__Lorem\n__Ipsum'
Creates an object from an array, using a function to map each value to a key.
- Use
Array.prototype.reduce()
to create an object fromarr
. - Apply
fn
to each value ofarr
to produce a key and add the key-value pair to the object.
const indexBy = (arr, fn) =>
arr.reduce((obj, v, i) => {
obj[fn(v, i, arr)] = v;
return obj;
}, {});
indexBy(
[
{ id: 10, name: "apple" },
{ id: 20, name: "orange" },
],
(x) => x.id
);
// { '10': { id: 10, name: 'apple' }, '20': { id: 20, name: 'orange' } }