But you should use Lodash.
It’s a great library, well crafted, battle tested and with a very skilled and active community contributing. The goal of this project is NOT to provide drop in replacements, but to show how to achieve similar functionalities in plain Javascript, to understand how things work behind the hood.
Being a learning platform, some implementations have been simplified to make them more digestible, and they might miss edge cases covered in the original version.
If you think something important is missing, or plain wrong, feel free to open an issue, just be aware we are not aiming at feature parity. There are also quite a few methods yet to be ported; please help contributing on github.
Creates an array of elements split into groups the length of size
. If array
can’t be split evenly, the final chunk will be the remaining elements.
// https://lodash.com/docs/#chunk
import { chunk } from 'lodash'
chunk(['a', 'b', 'c', 'd', 'e', 'f', 'g'])
// => [['a'], ['b'], ['c'], ['d'], ['e'], ['f'], ['g']]
chunk(['a', 'b', 'c', 'd', 'e', 'f', 'g'], 3)
// => [['a', 'b', 'c'], ['d', 'e', 'f'], ['g']]
chunk(['a', 'b', 'c', 'd', 'e', 'f', 'g'], 0)
// => []
chunk(['a', 'b', 'c', 'd', 'e', 'f', 'g'], -1)
// => []
const chunk = (arr, chunkSize = 1, cache = []) => {
const tmp = [...arr]
if (chunkSize <= 0) return cache
while (tmp.length) cache.push(tmp.splice(0, chunkSize))
return cache
}
chunk(['a', 'b', 'c', 'd', 'e', 'f', 'g'])
// => [['a'], ['b'], ['c'], ['d'], ['e'], ['f'], ['g']]
chunk(['a', 'b', 'c', 'd', 'e', 'f', 'g'], 3)
// => [['a', 'b', 'c'], ['d', 'e', 'f'], ['g']]
chunk(['a', 'b', 'c', 'd', 'e', 'f', 'g'], 0)
// => []
chunk(['a', 'b', 'c', 'd', 'e', 'f', 'g'], -1)
// => []
Resources: Spread syntax Array#splice
Creates an array with all falsey values removed. The values false
, null
, 0
, ""
, undefined
, and NaN
are falsey.
// https://lodash.com/docs/#compact
import { compact } from 'lodash'
compact([0, 1, 2])
// => [1, 2]
Creates a new array concatenating array
with any additional arrays and/or values.
// https://lodash.com/docs/#concat
import { concat } from 'lodash'
concat([1], 2, [3], [[4]])
// => [1, 2, 3, [4]]
Creates an array of array
values not included in the other given arrays.
// https://lodash.com/docs/#difference
import { difference } from 'lodash'
difference([2, 1], [3, 2])
// => [1]
const difference = (arr1, arr2) => arr1.filter(x => !arr2.includes(x))
difference([2, 1], [3, 2])
// => [1]
Resources: Array#filter Array#includes
This method is like _.difference
except that it accepts iteratee
which is invoked for each element of array
and values
to generate the criterion by which they’re compared. The order and references of result values are determined by the first array. The iteratee is invoked with one argument:
(value).
// https://lodash.com/docs/#differenceBy
import { differenceBy } from 'lodash'
differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor)
// => [1.2]
// The `_.property` iteratee shorthand.
differenceBy([{ x: 2 }, { x: 1 }], [{ x: 1 }], 'x')
// => [{ 'x': 2 }]
const differenceBy = (arr1, arr2, iteratee) => {
if (typeof iteratee === 'string') {
const prop = iteratee
iteratee = item => item[prop]
}
return arr1.filter(c => !arr2.map(iteratee).includes(iteratee(c)))
}
differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor)
// => [1.2]
// The `_.property` iteratee shorthand.
differenceBy([{ x: 2 }, { x: 1 }], [{ x: 1 }], 'x')
// => [{ 'x': 2 }]
Resources: Array#filter Array#includes
Creates a slice of array
with n
elements dropped from the beginning.
// https://lodash.com/docs/#drop
import { drop } from 'lodash'
drop([1, 2, 3])
// => [2, 3]
drop([1, 2, 3], 2)
// => [3]
drop([1, 2, 3], 5)
// => []
drop([1, 2, 3], 0)
// => [1, 2, 3]
const drop = (arr, n = 1) => arr.slice(n)
drop([1, 2, 3])
// => [2, 3]
drop([1, 2, 3], 2)
// => [3]
drop([1, 2, 3], 5)
// => []
drop([1, 2, 3], 0)
// => [1, 2, 3]
Resources: Default parameters Array#slice
Creates a slice of array
with n
elements dropped from the end.
// https://lodash.com/docs/#dropRight
import { dropRight } from 'lodash'
dropRight([1, 2, 3])
// => [1, 2]
dropRight([1, 2, 3], 2)
// => [1]
dropRight([1, 2, 3], 5)
// => []
dropRight([1, 2, 3], 0)
// => [1, 2, 3]
const dropRight = (arr, n = 1) => arr.slice(0, -n || arr.length)
dropRight([1, 2, 3])
// => [1, 2]
dropRight([1, 2, 3], 2)
// => [1]
dropRight([1, 2, 3], 5)
// => []
dropRight([1, 2, 3], 0)
// => [1, 2, 3]
Resources: Default parameters Array#slice
Fills elements of array
with value
from start
up to, but not including, end
.
// https://lodash.com/docs/#fill
import { fill } from 'lodash'
fill([1, 2, 3], 'a')
// => ['a', 'a', 'a']
fill(Array(3), 2)
// => [2, 2, 2]
fill([4, 6, 8, 10], '*', 1, 3)
// => [4, '*', '*', 10]
[1, 2, 3].fill('a')
// => ['a', 'a', 'a']
Array(3).fill(2)
// => [2, 2, 2]
[4, 6, 8, 10].fill('*', 1, 3)
// => [4, '*', '*', 10]
Resources: Array#find Source
This method is like _.find
except that it returns the index of the first element predicate
returns truthy for instead of the element itself.
// https://lodash.com/docs/#findIndex
import { findIndex } from 'lodash'
const users = [
{ user: 'barney', age: 36, active: true },
{ user: 'fred', age: 40, active: false },
{ user: 'pebbles', age: 1, active: true },
]
findIndex(users, o => o.age >= 40)
// => 1
const users = [
{ user: 'barney', age: 36, active: true },
{ user: 'fred', age: 40, active: false },
{ user: 'pebbles', age: 1, active: true },
]
users.findIndex(o => o.age >= 40)
// => 1
Resources: Array#findIndex Source
This method is like _.findIndex
except that it iterates over elements of collection
from right to left.
// https://lodash.com/docs/#findLastIndex
import { findLastIndex } from 'lodash'
const users = [
{ user: 'barney', active: true },
{ user: 'fred', active: false },
{ user: 'pebbles', active: false },
]
findLastIndex(users, o => !o.active)
// => 2
findLastIndex(users, o => !o.user)
// => -1
const users = [
{ user: 'barney', active: true },
{ user: 'fred', active: false },
{ user: 'pebbles', active: false },
]
users.findLastIndex(o => !o.active)
// => 2
users.findLastIndex(o => !o.user)
// => -1
Resources: Array#findLastIndex
Returns a new array formed by applying a given callback function to each element of the array, and then flattening the result by one level.
// https://lodash.com/docs/#flatMap
import { flatMap } from 'lodash'
flatMap([1, 2], n => [n, n])
// => [1, 1, 2, 2]
Flattens array
a single level deep.
// https://lodash.com/docs/#flatten
import { flatten } from 'lodash'
flatten([1, [2, [3, [4]], 5]])
// => [1, 2, [3, [4]], 5]
Recursively flattens array
.
// https://lodash.com/docs/#flattenDeep
import { flattenDeep } from 'lodash'
flattenDeep([1, [2, [3, [4]], 5]])
// => [1, 2, 3, 4, 5]
Recursively flatten array
up to depth
times.
// https://lodash.com/docs/#flattenDepth
import { flattenDepth } from 'lodash'
var array = [1, [2, [3, [4]], 5]]
flattenDepth(array, 1)
// => [1, 2, [3, [4]], 5]
flattenDepth(array, 2)
// => [1, 2, 3, [4], 5]
const flattenDepth = (arr, depth) => arr.flat(depth)
var array = [1, [2, [3, [4]], 5]]
flattenDepth(array, 1)
// => [1, 2, [3, [4]], 5]
flattenDepth(array, 2)
// => [1, 2, 3, [4], 5]
Resources: Array#flat
The inverse of _.toPairs
; this method returns an object composed from key-value pairs
.
// https://lodash.com/docs/#fromPairs
import { fromPairs } from 'lodash'
fromPairs([
['a', 1],
['b', 2],
])
// => { 'a': 1, 'b': 2 }
Object.fromEntries([
['a', 1],
['b', 2],
])
// => { 'a': 1, 'b': 2 }
Resources: Object.fromEntries
Gets the first element of array
.
// https://lodash.com/docs/#head
import { head } from 'lodash'
head([1, 2, 3])
// => 1
Gets the index at which the first occurrence of value
is found in array
.
// https://lodash.com/docs/#indexOf
import { indexOf } from 'lodash'
indexOf([1, 2, 3], 3)
// => 2
Gets all but the last element of array
.
// https://lodash.com/docs/#initial
import { initial } from 'lodash'
initial([1, 2, 3])
// => [1, 2]
Creates an array of unique values that are included in all given arrays.
// https://lodash.com/docs/#intersection
import { intersection } from 'lodash'
intersection([2, 1], [2, 3])
// => [2]
const intersection = (arr, ...args) =>
arr.filter(item => args.every(arr => arr.includes(item)))
intersection([2, 1], [2, 3])
// => [2]
Resources: Spread syntax Array#filter Array#every
This method is like _.intersection
except that it accepts iteratee
which is invoked for each element of each arrays
to generate the criterion by which they’re compared. The order and references of result values are determined by the first array. The iteratee is invoked with one argument:
(value).
// https://lodash.com/docs/#intersectionBy
import { intersectionBy } from 'lodash'
intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor)
// => [2.1]
// The `_.property` iteratee shorthand.
intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x')
// => [{ 'x': 1 }]
const intersectionBy = (arr, ...args) => {
let iteratee = args.pop()
if (typeof iteratee === 'string') {
const prop = iteratee
iteratee = item => item[prop]
}
return arr.filter(item1 =>
args.every(arr2 => arr2.find(item2 => iteratee(item1) === iteratee(item2)))
)
}
intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor)
// => [2.1]
// The `_.property` iteratee shorthand.
intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x')
// => [{ 'x': 1 }]
Resources: Spread syntax Array#pop Array#filter Array#every Array#find
Converts all elements in array
into a string separated by separator
.
// https://lodash.com/docs/#join
import { join } from 'lodash'
join(['a', 'b', 'c'], '~')
// => 'a~b~c'
Gets the last element of array
.
// https://lodash.com/docs/#last
import { last } from 'lodash'
last(['a', 'b', 'c'])
// => 'c'
const arr = ['a', 'b', 'c']
arr[arr.length - 1]
// => 'c'
This method is like _.indexOf
except that it iterates over elements of array
from right to left.
// https://lodash.com/docs/#lastIndexOf
import { lastIndexOf } from 'lodash'
lastIndexOf([1, 2, 1, 2], 2)
// => 3
// Search from the `fromIndex`
lastIndexOf([1, 2, 1, 2], 2, 2)
// => 1
[1, 2, 1, 2].lastIndexOf(2)
// => 3
// Search from the `fromIndex`
[1, 2, 1, 2].lastIndexOf(2, 2)
// => 1
Resources: Array#lastIndexOf
Gets the element at index n
of array
. If n
is negative, the nth element from the end is returned.
// https://lodash.com/docs/#nth
import { nth } from 'lodash'
const array = ['a', 'b', 'c', 'd']
nth(array, 1)
// => 'b'
nth(array, -2)
// => 'c';
const nth = (arr, idx) => arr.slice(idx, idx + 1)[0]
const array = ['a', 'b', 'c', 'd']
nth(array, 1)
// => 'b'
nth(array, -2)
// => 'c';
Resources: Array#slice
Removes all given values from array
using SameValueZero
for equality comparisons.
Note: Unlike .without
, this method mutates array
. Use .remove
to remove elements from an array by predicate.
// https://lodash.com/docs/#pull
import { pull } from 'lodash'
var array = ['a', 'b', 'c', 'a', 'b', 'c']
pull(array, 'a', 'c')
array
// => ['b', 'b']
const pull = (array, ...values) => {
values.forEach(value => {
while (array.includes(value)) {
array.splice(array.indexOf(value), 1)
}
})
return array
}
var array = ['a', 'b', 'c', 'a', 'b', 'c']
pull(array, 'a', 'c')
array
// => ['b', 'b']
Resources: Spread syntax Array#forEach Array#includes Array#splice Array#indexOf
Removes elements from array
corresponding to indexes
and returns an array of removed elements.
// https://lodash.com/docs/#pullAt
import { pullAt } from 'lodash'
const array = ['a', 'b', 'c', 'd']
pullAt(array, [1, 3])
// => ['b', 'd']
array
// => ['a', 'c']
const pullAt = (arr, idxs) =>
idxs
.reverse()
.map(idx => arr.splice(idx, 1)[0])
.reverse()
const array = ['a', 'b', 'c', 'd']
pullAt(array, [1, 3])
// => ['b', 'd']
array
// => ['a', 'c']
Resources: Array#reverse Array#splice
The opposite of _.filter
; this method returns the elements of collection
that predicate
does not return truthy for.
// https://lodash.com/docs/#reject
import { reject } from 'lodash'
reject(
['a', 'b', 'c', 'd', 'e', 'f', 'g'],
char => char === 'd'
)
// => [['a', 'b', 'c', 'e', 'f', 'g']]
['a', 'b', 'c', 'd', 'e', 'f', 'g'].filter(
char => char !== 'd'
)
// => [['a', 'b', 'c', 'e', 'f', 'g']]
Resources: Array#filter
Removes all elements from array
that predicate
returns truthy for and returns an array of the removed elements. The predicate is invoked with three arguments: (value, index, array).
// https://lodash.com/docs/#remove
import { remove } from 'lodash'
const array = [1, 2, 3, 4]
const evens = remove(array, n => {
return n % 2 === 0
})
array
// => [1, 3]
evens
// => [2, 4]
const newArray = [1, 2, 3, 4, 5]
remove(newArray, () => newArray.length > 0)
// => [1, 2, 3, 4, 5]
newArray
// => []
const remove = (array, iteratee) => {
// in order to not mutate the original array until the very end
// we want to cache the indexes to remove while preparing the result to return
const toRemove = []
const result = array.filter((item, i) => iteratee(item) && toRemove.push(i))
// just before returning, we can then remove the items, making sure we start
// from the higher indexes: otherwise they would shift at each removal
toRemove.reverse().forEach(i => array.splice(i, 1))
return result
}
const array = [1, 2, 3, 4]
const evens = remove(array, n => {
return n % 2 === 0
})
array
// => [1, 3]
evens
// => [2, 4]
const newArray = [1, 2, 3, 4, 5]
remove(newArray, () => newArray.length > 0)
// => [1, 2, 3, 4, 5]
newArray
// => []
Resources: Array#filter Array#splice
Reverses array
so that the first element becomes the last, the second element becomes the second to last, and so on.
// https://lodash.com/docs/#reverse
import { reverse } from 'lodash'
const array = [1, 2, 3]
reverse(array)
// => [3, 2, 1]
array
// => [3, 2, 1]
const array = [1, 2, 3]
array.reverse()
// => [3, 2, 1]
array
// => [3, 2, 1]
Resources: Array#reverse
Creates a slice of array
from start
up to, but not including, end
.
Note: This method is used instead of Array#slice
to ensure dense arrays are returned.
// https://lodash.com/docs/#slice
import { slice } from 'lodash'
slice([1, 2, 3, 4], 2, 6)
// => [ 3, 4 ]
const array = []
array[6] = 6
array[9] = 9
slice(array, 2, 6)
// => [ undefined, undefined, undefined, undefined ]
const slice = (arr, start, end) => [...arr.slice(start, end)]
slice([1, 2, 3, 4], 2, 6)
// => [ 3, 4 ]
const array = []
array[6] = 6
array[9] = 9
slice(array, 2, 6)
// => [ undefined, undefined, undefined, undefined ]
Resources: Sparse vs Dense Arrays
This method is like _.indexOf
except that it performs the search on a sorted array
.
// https://lodash.com/docs/#sortedIndexOf
import { sortedIndexOf } from 'lodash'
sortedIndexOf([4, 5, 5, 5, 6], 5)
// => 1
const sortedIndexOf = (arr, value) => [...arr].sort().indexOf(value)
sortedIndexOf([4, 5, 5, 5, 6], 5)
// => 1
Resources: Array#sort Array#indexOf
This method is like _.sortedIndex
except that it returns the highest index at which value
should be inserted into array
in order to maintain its sort order.
// https://lodash.com/docs/#sortedLastIndexOf
import { sortedLastIndexOf } from 'lodash'
sortedLastIndexOf([4, 5, 5, 5, 6], 5)
// => 3
// https://lodash.com/docs/#sortedLastIndexOf
const sortedLastIndexOf = (arr, value) => [...arr].sort().lastIndexOf(value)
sortedLastIndexOf([4, 5, 5, 5, 6], 5)
// => 3
Resources: Array#sort Array#lastIndexOf
This method is like _.uniq
except that it’s designed and optimized for sorted arrays.
// https://lodash.com/docs/#sortedUniq
import { sortedUniq } from 'lodash'
sortedUniq([1, 1, 2])
// => [1, 2]
const sortedUniq = arr => [...new Set(arr)].sort()
sortedUniq([1, 1, 2])
// => [1, 2]
Resources: Set Array#sort
Gets all but the first element of array
.
// https://lodash.com/docs/#tail
import { tail } from 'lodash'
tail([1, 2, 3])
// => [2, 3]
Creates a slice of array
with n
elements taken from the beginning.
// https://lodash.com/docs/#take
import { take } from 'lodash'
take([1, 2, 3])
// => [1]
take([1, 2, 3], 2)
// => [1, 2]
take([1, 2, 3], 5)
// => [1, 2, 3]
take([1, 2, 3], 0)
// => []
const take = (arr, qty = 1) => [...arr].splice(0, qty)
take([1, 2, 3])
// => [1]
take([1, 2, 3], 2)
// => [1, 2]
take([1, 2, 3], 5)
// => [1, 2, 3]
take([1, 2, 3], 0)
// => []
Resources: Default parameters Spread syntax Array#splice
Creates a slice of array
with n
elements taken from the end.
// https://lodash.com/docs/#takeRight
import { takeRight } from 'lodash'
takeRight([1, 2, 3])
// => [3]
takeRight([1, 2, 3], 2)
// => [2, 3]
takeRight([1, 2, 3], 5)
// => [1, 2, 3]
takeRight([1, 2, 3], 0)
// => []
const takeRight = (arr, qty = 1) => [...arr].splice(-qty, qty)
takeRight([1, 2, 3])
// => [3]
takeRight([1, 2, 3], 2)
// => [2, 3]
takeRight([1, 2, 3], 5)
// => [1, 2, 3]
takeRight([1, 2, 3], 0)
// => []
Resources: Default parameters Spread syntax Array#splice
Creates an array of own enumerable string keyed-value pairs for object
which can be consumed by _.fromPairs
. If object
is a map or set, its entries are returned.
// https://lodash.com/docs/#toPairs
import { toPairs } from 'lodash'
function Foo() {
this.a = 1
this.b = 2
}
Foo.prototype.c = 3
toPairs(new Foo())
// => [['a', 1], ['b', 2]] (iteration order is not guaranteed)
function Foo() {
this.a = 1
this.b = 2
}
Foo.prototype.c = 3
Object.entries(new Foo())
// => [['a', 1], ['b', 2]] (iteration order is not guaranteed)
Resources: Object.entries
Creates an array of unique values, in order, from all given arrays.
// https://lodash.com/docs/#union
import { union } from 'lodash'
union([2], [1, 2], [1, 2])
// => [2, 1]
const union = (arr, ...args) => [...new Set(arr.concat(...args))]
union([2], [1, 2], [1, 2])
// => [2, 1]
Resources: Spread syntax Set
This method is like _.union
except that it accepts iteratee
which is invoked for each element of each arrays
to generate the criterion by which uniqueness is computed. Result values are chosen from the first array in which the value occurs. The iteratee is invoked with one argument:
(value).
// https://lodash.com/docs/#unionBy
import { unionBy } from 'lodash'
unionBy([2.1], [1.2, 2.3], Math.floor)
// => [2.1, 1.2]
// The `_.property` iteratee shorthand.
unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x')
// => [{ 'x': 1 }, { 'x': 2 }]
// _.uniqBy example
unionBy([2.1, 1.2, 2.3], Math.floor)
// => [2.1, 1.2]
// This implementation also works for
// https://youmightnotneed.com/lodash#uniqBy
// by passing only one array as an argument
// before the iteratee function
const unionBy = (arr, ...args) => {
let iteratee = args.pop()
if (typeof iteratee === 'string') {
const prop = iteratee
iteratee = item => item[prop]
}
return arr
.concat(...args)
.filter(
(x, i, self) => i === self.findIndex(y => iteratee(x) === iteratee(y))
)
}
unionBy([2.1], [1.2, 2.3], Math.floor)
// => [2.1, 1.2]
// The `_.property` iteratee shorthand.
unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x')
// => [{ 'x': 1 }, { 'x': 2 }]
// _.uniqBy example
unionBy([2.1, 1.2, 2.3], Math.floor)
// => [2.1, 1.2]
Resources: Spread syntax Array#pop Array#concat Array#filter Array#findIndex
Creates a duplicate-free version of an array, in which only the first occurrence of each element is kept. The order of result values is determined by the order they occur in the array.
// https://lodash.com/docs/#uniq
import { uniq } from 'lodash'
uniq([2, 1, 2])
// => [2, 1]
This method is like _.uniq
except that it accepts iteratee
which is invoked for each element in array
to generate the criterion by which uniqueness is computed. The order of result values is determined by the order they occur in the array. The iteratee is invoked with one argument:
(value).
// https://lodash.com/docs/#uniqBy
import { uniqBy } from 'lodash'
uniqBy([2.1, 1.2, 2.3], Math.floor)
// => [2.1, 1.2]
// The `_.property` iteratee shorthand.
uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x')
// => [{ 'x': 1 }, { 'x': 2 }]
// This is a simplified implementation
// of https://youmightnotneed.com/lodash#unionBy
// which would work with only one array
const uniqBy = (arr, iteratee) => {
if (typeof iteratee === 'string') {
const prop = iteratee
iteratee = item => item[prop]
}
return arr.filter(
(x, i, self) => i === self.findIndex(y => iteratee(x) === iteratee(y))
)
}
uniqBy([2.1, 1.2, 2.3], Math.floor)
// => [2.1, 1.2]
// The `_.property` iteratee shorthand.
uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x')
// => [{ 'x': 1 }, { 'x': 2 }]
Resources: Spread syntax Array#filter Array#findIndex
This method is like _.zip
except that it accepts an array of grouped elements and creates an array regrouping the elements to their pre-zip configuration.
// https://lodash.com/docs/#unzip
import { unzip } from 'lodash'
unzip([
['a', 1, true],
['b', 2, false],
])
// => [['a', 'b'], [1, 2], [true, false]]
const zip = (arr, ...args) =>
arr.map((value, idx) => [value, ...args.map(arr => arr[idx])])
const unzip = ([...args]) => zip(...args)
unzip([
['a', 1, true],
['b', 2, false],
])
// => [['a', 'b'], [1, 2], [true, false]]
Resources: Spread syntax Array#map
Creates an array excluding all given values.
// https://lodash.com/docs/#without
import { without } from 'lodash'
const array = [2, 1, 2, 3]
without(array, 1, 2)
// => [3]
array
// => [2, 1, 2, 3]
const without = (arr, ...args) => arr.filter(item => !args.includes(item))
const array = [2, 1, 2, 3]
without(array, 1, 2)
// => [3]
array
// => [2, 1, 2, 3]
Resources: Spread syntax Array#filter Array#includes
Creates an array of unique values that is the symmetric difference of the given arrays. The order of result values is determined by the order they occur in the arrays.
// https://lodash.com/docs/#xor
import { xor } from 'lodash'
xor([2, 1, 4], [2, 3, 2, 6])
// => [1, 4, 3, 6]
xor([1, 1, 2], [2, 2, 3])
// => [1, 3]
xor([1], [2], [1, 3], [2, 4])
// => [3, 4]
// this function can be used as a standalone xor if you only
// ever need it to work with two arguments
const binaryXor = (arr1, arr2) => {
const a = arr1.filter(x => !arr2.includes(x))
const b = arr2.filter(x => !arr1.includes(x))
return Array.from(new Set([...a, ...b]))
}
const xor = (...arrays) => arrays.reduce(binaryXor, [])
xor([2, 1, 4], [2, 3, 2, 6])
// => [1, 4, 3, 6]
xor([1, 1, 2], [2, 2, 3])
// => [1, 3]
xor([1], [2], [1, 3], [2, 4])
// => [3, 4]
Resources: Array#filter Array#includes
Creates an array of grouped elements, the first of which contains the first elements of the given arrays, the second of which contains the second elements of the given arrays, and so on.
// https://lodash.com/docs/#zip
import { zip } from 'lodash'
zip(['a', 'b'], [1, 2], [true, false])
// => [['a', 1, true], ['b', 2, false]]
const zip = (arr, ...args) =>
arr.map((value, idx) => [value, ...args.map(arr => arr[idx])])
zip(['a', 'b'], [1, 2], [true, false])
// => [['a', 1, true], ['b', 2, false]]
Resources: Spread syntax Array#map
This method is like _.fromPairs except that it accepts two arrays, one of property identifiers and one of corresponding values.
// https://lodash.com/docs/#zipObject
import { zipObject } from 'lodash'
zipObject(['a', 'b'], [1, 2])
// => { 'a': 1, 'b': 2 }
const zipObject = (keys, values) =>
keys.reduce((acc, key, idx) => {
acc[key] = values[idx]
return acc
}, {})
zipObject(['a', 'b'], [1, 2])
// => { 'a': 1, 'b': 2 }
Resources: Array#reduce
Checks if predicate
returns truthy for all elements of collection
. Iteration is stopped once predicate
returns falsey. The predicate is invoked with three arguments: (value, index|key, collection).
// https://lodash.com/docs/#every
import { every } from 'lodash'
function isLargerThanTen(element) {
return element >= 10
}
every([10, 20, 30], isLargerThanTen)
// => true
function isLargerThanTen(element) {
return element >= 10
}
[10, 20, 30].every(isLargerThanTen)
// => true
Resources: Array#every Source
Iterates over elements of collection
, returning an array of all elements predicate
returns truthy for. The predicate is invoked with three arguments: (value, index|key, collection).
// https://lodash.com/docs/#filter
import { filter } from 'lodash'
function isBigEnough(value) {
return value >= 10
}
filter([12, 5, 8, 130, 44], isBigEnough)
// => [12, 130, 44]
function isBigEnough(value) {
return value >= 10
}
[12, 5, 8, 130, 44].filter(isBigEnough)
// => [12, 130, 44]
Resources: Array#filter Source
Iterates over elements of collection
, returning the first element predicate
returns truthy for. The predicate is invoked with three arguments: (value, index|key, collection).
// https://lodash.com/docs/#find
import { find } from 'lodash'
const users = [
{ user: 'barney', age: 36, active: true },
{ user: 'fred', age: 40, active: false },
{ user: 'pebbles', age: 1, active: true },
]
find(users, o => o.age < 40)
// => { user: "barney", age: 36, active: true }
const users = [
{ user: 'barney', age: 36, active: true },
{ user: 'fred', age: 40, active: false },
{ user: 'pebbles', age: 1, active: true },
]
users.find(o => o.age < 40)
// => { user: "barney", age: 36, active: true }
Resources: Array#find Source
Iterates over elements of collection
and invokes iteratee
for each element. The iteratee is invoked with three arguments: (value, index|key, collection). Iteratee functions may exit iteration early by explicitly returning false
.
// https://lodash.com/docs/#forEach
import { forEach } from 'lodash'
const array = ['a', 'b', 'c']
forEach(array, (item, index) => {
console.log(item, index)
})
// => a 0
// => b 1
// => c 2
;['a', 'b', 'c'].forEach((item, index) => {
console.log(item, index)
})
// => a 0
// => b 1
// => c 2
Resources: Array#forEach Source
This method is like _.forEach
except that it iterates over elements of collection
from right to left.
// https://lodash.com/docs/#forEachRight
import { forEachRight } from 'lodash'
const array = ['a', 'b', 'c']
forEachRight(array, (item, index) => {
console.log(item, index)
})
// => c 2
// => b 1
// => a 0
const forEachRight = (array, iteratee) =>
[...array].reverse().forEach((val, index) => {
iteratee(val, array.length - 1 - index, array)
})
const array = ['a', 'b', 'c']
forEachRight(array, (item, index) => {
console.log(item, index)
})
// => c 2
// => b 1
// => a 0
Resources: Spread syntax Array#reverse Array#forEach
Checks if value
is in collection
. If collection
is a string, it’s checked for a substring of value
. If fromIndex
is negative, it’s used as the offset from the end of collection
.
// https://lodash.com/docs/#includes
import { includes } from 'lodash'
includes([1, 2, 3], 1)
// => true
Creates an array of values by running each element in collection
thru iteratee
. The iteratee is invoked with three arguments:
(value, index|key, collection).
// https://lodash.com/docs/#map
import { map } from 'lodash'
map([1, 2, 3], n => n * 3)
// => [3, 6, 9]
Reduces collection
to a value which is the accumulated result of running each element in collection
thru iteratee
, where each successive invocation is supplied the return value of the previous. If accumulator
is not given, the first element of collection
is used as the initial value. The iteratee is invoked with four arguments:
(accumulator, value, index|key, collection).
// https://lodash.com/docs/#reduce
import { reduce } from 'lodash'
reduce([1, 2], (sum, n) => sum + n, 0)
// => 3
reduce(
{ a: 1, b: 2, c: 1 },
(result, value, key) => {
;(result[value] || (result[value] = [])).push(key)
return result
},
{}
)
// => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed)
[1, 2].reduce((sum, n) => sum + n, 0)
// => 3
Object.entries({ a: 1, b: 2, c: 1 }).reduce(
(result, [key, value]) => {
;(result[value] || (result[value] = [])).push(key)
return result
},
{}
)
// => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed)
Resources: Object.entries Array#reduce
This method is like _.reduce
except that it iterates over elements of collection
from right to left.
// https://lodash.com/docs/#reduceRight
import { reduceRight } from 'lodash'
reduceRight(
[
[0, 1],
[2, 3],
[4, 5],
],
(flattened, other) => flattened.concat(other),
[]
)
// => [4, 5, 2, 3, 0, 1]
[
[0, 1],
[2, 3],
[4, 5],
].reduceRight((flattened, other) => flattened.concat(other), [])
// => [4, 5, 2, 3, 0, 1]
Resources: Array#reduceRight Source
Gets the size of collection
by returning its length for array-like values or the number of own enumerable string keyed properties for objects.
// https://lodash.com/docs/#size
import { size } from 'lodash'
size([1, 2, 3])
// => 3
size({ a: 1, b: 2 })
// => 2
size('pebbles')
// => 7
const size = item =>
item.constructor === Object ? Object.keys(item).length : item.length
size([1, 2, 3])
// => 3
size({ a: 1, b: 2 })
// => 2
size('pebbles')
// => 7
Resources: Object.keys Source
Checks if predicate
returns truthy for any element of collection
. Iteration is stopped once predicate
returns truthy. The predicate is invoked with three arguments: (value, index|key, collection).
// https://lodash.com/docs/#some
import { some } from 'lodash'
const isEven = n => n % 2 === 0
some([3, 4, 5], isEven)
// => true
Gets the timestamp of the number of milliseconds that have elapsed since the Unix epoch (1 January 1970 00
:00:00 UTC).
// https://lodash.com/docs/#now
import { now } from 'lodash'
now()
// => # milliseconds elapsed since the Unix epoch
The opposite of _.before
; this method creates a function that invokes func
once it’s called n
or more times.
// https://lodash.com/docs/#after
import { after } from 'lodash'
(times, fn) => after(times, fn)
const after = (times, fn) => {
let counter = 0
return (...args) => {
counter++
if (counter >= times) {
return fn(...args)
}
}
}
(times, fn) => after(times, fn)
Resources: Spread syntax
Creates a function that invokes func
, with up to n
arguments, ignoring any additional arguments.
// https://lodash.com/docs/#ary
import { ary } from 'lodash'
['6', '8', '10'].map(ary(Number.parseInt, 1))
// => [6, 8, 10]
const ary =
(fn, arity) =>
(...args) =>
fn(...args.slice(0, arity))
['6', '8', '10'].map(ary(Number.parseInt, 1))
// => [6, 8, 10]
Resources: Spread syntax
Creates a function that invokes func
, with the this
binding and arguments of the created function, while it’s called less than n
times. Subsequent calls to the created function return the result of the last func
invocation.
// https://lodash.com/docs/#before
import { before } from 'lodash'
(times, fn) => before(times, fn)
const before = (times, fn) => {
let counter = 0
let res
return (...args) => {
counter++
if (counter < times) {
res = fn(...args)
return res
} else {
return res
}
}
}
(times, fn) => before(times, fn)
Resources: Spread syntax
Creates a function that invokes func
with the this
binding of thisArg
and partials
prepended to the arguments it receives.
// https://lodash.com/docs/#bind
import { bind } from 'lodash'
function greet(greeting, punctuation) {
return greeting + ' ' + this.user + punctuation
}
var object = { user: 'fred' }
var bound = bind(greet, object, 'hi')
bound('!')
// => 'hi fred!'
const bind = (fn, ctx, ...boundArgs) => fn.bind(ctx, ...boundArgs)
function greet(greeting, punctuation) {
return greeting + ' ' + this.user + punctuation
}
var object = { user: 'fred' }
var bound = bind(greet, object, 'hi')
bound('!')
// => 'hi fred!'
Resources: Spread syntax Function#bind
Creates a function that invokes the method at object[key]
with partials
prepended to the arguments it receives.
This method differs from .bind
by allowing bound functions to reference methods that may be redefined or don’t yet exist. See Peter Michaux’s article for more details.
The .bindKey.placeholder
value, which defaults to _
in monolithic builds, may be used as a placeholder for partially applied arguments.
// https://lodash.com/docs/#bindKey
import { bindKey } from 'lodash'
const object = {
'user': 'fred',
'greet': function (greeting, punctuation) {
return greeting + ' ' + this.user + punctuation
},
}
let bound = bindKey(object, 'greet', 'hi')
bound('!')
// => 'hi fred!'
object.greet = function (greeting, punctuation) {
return greeting + 'ya ' + this.user + punctuation
}
bound('!')
// => 'hiya fred!'
const bindKey =
(obj, method, ...args) =>
(...bound) =>
obj[method](...args, ...bound)
const object = {
'user': 'fred',
'greet': function (greeting, punctuation) {
return greeting + ' ' + this.user + punctuation
},
}
let bound = bindKey(object, 'greet', 'hi')
bound('!')
// => 'hi fred!'
object.greet = function (greeting, punctuation) {
return greeting + 'ya ' + this.user + punctuation
}
bound('!')
// => 'hiya fred!'
Resources: Spread
Creates a function that accepts arguments of func
and either invokes func
returning its result, if at least arity
number of arguments have been provided, or returns a function that accepts the remaining func
arguments, and so on. The arity of func
may be specified if func.length
is not sufficient.
The .curry.placeholder
value, which defaults to in monolithic builds, may be used as a placeholder for provided arguments.
// https://lodash.com/docs/#curry
import { curry } from 'lodash'
const abc = (a, b, c) => [a, b, c]
const curried = curry(abc)
curried(1)(2)(3)
// => [1, 2, 3]
curried(1, 2)(3)
// => [1, 2, 3]
curried(1, 2, 3)
// => [1, 2, 3]
const curry = func => {
// define the number of expected arguments
const expectedArgs = func.length
const curried = (...args) => {
// if enough arugments has been passed return the
// result of the function execution, otherwise
// continue adding arguments to the list
return args.length >= expectedArgs
? func(...args)
: (...args2) => curried(...args.concat(args2))
}
return curried
}
const abc = (a, b, c) => [a, b, c]
const curried = curry(abc)
curried(1)(2)(3)
// => [1, 2, 3]
curried(1, 2)(3)
// => [1, 2, 3]
curried(1, 2, 3)
// => [1, 2, 3]
Resources: Spread syntax learn-js
This method is like .curry
except that arguments are applied to func
in the manner of .partialRight
instead of .partial
.
The .curryRight.placeholder
value, which defaults to _
in monolithic builds, may be used as a placeholder for provided arguments.
// https://lodash.com/docs/#curryRight
import { curryRight } from 'lodash'
const abc = (a, b, c) => [a, b, c]
const curried = curryRight(abc)
curried(3)(2)(1)
// => [1, 2, 3]
curried(2, 3)(1)
// => [1, 2, 3]
curried(1, 2, 3)
// => [1, 2, 3]
// the only difference from the curry method
// implementation is how arguments gets concatenated
const curryRight = func => {
const expectedArgs = func.length
const curried = (...args) => {
return args.length >= expectedArgs
? func(...args)
: (...args2) => curried(...args2.concat(args))
}
return curried
}
const abc = (a, b, c) => [a, b, c]
const curried = curryRight(abc)
curried(3)(2)(1)
// => [1, 2, 3]
curried(2, 3)(1)
// => [1, 2, 3]
curried(1, 2, 3)
// => [1, 2, 3]
Resources: learn-js
Creates a debounced function that delays invoking func
until after wait
milliseconds have elapsed since the last time the debounced function was invoked.
// https://lodash.com/docs/#debounce
import { debounce } from 'lodash'
(...args) => debounce(...args)
const debounce = (func, delay, { leading } = {}) => {
let timerId
return (...args) => {
if (!timerId && leading) {
func(...args)
}
clearTimeout(timerId)
timerId = setTimeout(() => func(...args), delay)
}
}
(...args) => debounce(...args)
Resources: Spread syntax Debounce vs Throttle demo
Invokes func
after wait
milliseconds. Any additional arguments are provided to func
when it’s invoked.
// https://lodash.com/docs/#delay
import { delay } from 'lodash'
fn => delay(fn, 1000, 'later')
const delay = (fn, timer, ...args) => setTimeout(() => fn(...args), timer)
fn => delay(fn, 1000, 'later')
Resources: Spread syntax
Creates a function that invokes func
with arguments reversed.
// https://lodash.com/docs/#flip
import { flip } from 'lodash'
const flipped = flip((...args) => args)
flipped('a', 'b', 'c', 'd')
// => ['d', 'c', 'b', 'a']
const flip =
func =>
(...args) =>
func(...args.reverse())
const flipped = flip((...args) => args)
flipped('a', 'b', 'c', 'd')
// => ['d', 'c', 'b', 'a']
Resources: Spread syntax
Creates a function that negates the result of the predicate func
. The func
predicate is invoked with the this
binding and arguments of the created function.
// https://lodash.com/docs/#negate
import { negate } from 'lodash'
const isEven = n => n % 2 === 0
[1, 2, 3, 4, 5, 6].filter(negate(isEven))
// => [1, 3, 5]
const negate =
func =>
(...args) =>
!func(...args)
const isEven = n => n % 2 === 0
[1, 2, 3, 4, 5, 6].filter(negate(isEven))
// => [1, 3, 5]
Resources: Spread syntax
Creates a function that is restricted to invoking func
once. Repeat calls to the function return the value of the first invocation.
// https://lodash.com/docs/#once
import { once } from 'lodash'
fn => once(fn)
const once = fn => {
let called = false
let result
return (...args) => {
if (!called) {
result = fn(...args)
called = true
}
return result
}
}
fn => once(fn)
Resources: Spread syntax
Creates a function that invokes func
with its arguments transformed.
// https://lodash.com/docs/#overArgs
import { overArgs } from 'lodash'
function doubled(n) {
return n * 2
}
function square(n) {
return n * n
}
const func = overArgs(
function (x, y) {
return [x, y]
},
[square, doubled]
)
func(9, 3)
// => [81, 6]
func(10, 5)
// => [100, 10]
const overArgs =
(fn, ops) =>
(...args) => {
const mappedArgs = args.map((arg, i) => (ops[i] ? ops[i](arg) : arg))
return fn(...mappedArgs)
}
function doubled(n) {
return n * 2
}
function square(n) {
return n * n
}
const func = overArgs(
function (x, y) {
return [x, y]
},
[square, doubled]
)
func(9, 3)
// => [81, 6]
func(10, 5)
// => [100, 10]
Resources: Spread syntax Array#map
Creates a function that invokes func
with partials
prepended to the arguments it receives.
// https://lodash.com/docs/#partial
import { partial } from 'lodash'
const greet = (greeting, name) => `${greeting} ${name}`
const sayHelloTo = partial(greet, 'hello')
sayHelloTo('fred')
// => 'hello fred'
const partial =
(func, ...args) =>
(...furtherArgs) =>
func(...args, ...furtherArgs)
const greet = (greeting, name) => `${greeting} ${name}`
const sayHelloTo = partial(greet, 'hello')
sayHelloTo('fred')
// => 'hello fred'
This method is like _.partial
except that partially applied arguments are appended to the arguments it receives.
// https://lodash.com/docs/#partialRight
import { partialRight } from 'lodash'
const greet = (greeting, name) => `${greeting} ${name}`
const greetFred = partialRight(greet, 'fred')
greetFred('hi')
// => 'hi fred'
const partialRight =
(func, ...cachedArgs) =>
(...args) =>
func(...args, ...cachedArgs)
const greet = (greeting, name) => `${greeting} ${name}`
const greetFred = partialRight(greet, 'fred')
greetFred('hi')
// => 'hi fred'
Resources: Spread syntax
Creates a function that invokes func
with arguments arranged according to the specified indexes
where the argument value at the first index is provided as the first argument, the argument value at the second index is provided as the second argument, and so on.
// https://lodash.com/docs/#rearg
import { rearg } from 'lodash'
const rearged = rearg((a, b, c) => [a, b, c], [2, 0, 1])
rearged('b', 'c', 'a')
// => ['a', 'b', 'c']
const rearg =
(func, order) =>
(...args) => {
const reargs = order.map(idx => args[idx])
return func(...reargs)
}
const rearged = rearg((a, b, c) => [a, b, c], [2, 0, 1])
rearged('b', 'c', 'a')
// => ['a', 'b', 'c']
Resources: Spread syntax
func
with the this
binding of the created function and arguments from start
and beyond provided as an array.// https://lodash.com/docs/#rest
import { rest } from 'lodash'
const say = rest(
(what, names) =>
what +
' ' +
names.slice(0, -1).join(', ') + // see _.initial
(names.length > 1 ? ', & ' : '') +
names[names.length - 1] // see _.last
)
say('hello', 'fred', 'barney', 'pebbles')
// => 'hello fred, barney, & pebbles'
const rest =
func =>
(first, ...args) =>
func(first, args)
const say = rest(
(what, names) =>
what +
' ' +
names.slice(0, -1).join(', ') + // see _.initial
(names.length > 1 ? ', & ' : '') +
names[names.length - 1] // see _.last
)
say('hello', 'fred', 'barney', 'pebbles')
// => 'hello fred, barney, & pebbles'
Creates a function that invokes func
with the this
binding of the create function and an array of arguments much like Function#apply
.
Note: This method is based on the spread operator.
// https://lodash.com/docs/#spread
import { spread } from 'lodash'
const say = spread(function (who, what) {
return who + ' says ' + what
})
say(['fred', 'hello'])
// => 'fred says hello'
const numbers = Promise.all([Promise.resolve(40), Promise.resolve(36)])
numbers.then(
spread(function (x, y) {
return x + y
})
)
// => a Promise of 76
const spread = func => args => func(...args)
const say = spread(function (who, what) {
return who + ' says ' + what
})
say(['fred', 'hello'])
// => 'fred says hello'
const numbers = Promise.all([Promise.resolve(40), Promise.resolve(36)])
numbers.then(
spread(function (x, y) {
return x + y
})
)
// => a Promise of 76
Resources: Spread
Creates a function that accepts up to one argument, ignoring any additional arguments.
// https://lodash.com/docs/#unary
import { unary } from 'lodash'
['6', '8', '10'].map(unary(Number.parseInt))
// => [6, 8, 10]
const unary = fn => arg => fn(arg)
['6', '8', '10'].map(unary(Number.parseInt))
// => [6, 8, 10]
Creates a function that provides value
to wrapper
as its first argument. Any additional arguments provided to the function are appended to those provided to the wrapper
.
// https://lodash.com/docs/#wrap
import { wrap } from 'lodash'
const sum2 = wrap(2, (a, b, c) => {
return a + b + c
})
sum2(1, 2)
// => 5
const wrap =
(value, func) =>
(...args) =>
func(value, ...args)
const sum2 = wrap(2, (a, b, c) => {
return a + b + c
})
sum2(1, 2)
// => 5
Resources: Spread syntax
Casts value
as an array if it’s not one.
// https://lodash.com/docs/#castArray
import { castArray } from 'lodash'
castArray(1)
// => [1]
castArray({ a: 1 })
// => [{ 'a': 1 }]
castArray('abc')
// => ['abc']
castArray(null)
// => [null]
castArray(undefined)
// => [undefined]
castArray()
// => []
const array = [1, 2, 3]
castArray(array) === array
// => true
const castArray = (...args) => (args[0] instanceof Array ? args[0] : args)
castArray(1)
// => [1]
castArray({ a: 1 })
// => [{ 'a': 1 }]
castArray('abc')
// => ['abc']
castArray(null)
// => [null]
castArray(undefined)
// => [undefined]
castArray()
// => []
const array = [1, 2, 3]
castArray(array) === array
// => true
Resources: instanceof Spread syntax
Checks if object
conforms to source
by invoking the predicate properties of source
with the corresponding property values of object
.
// https://lodash.com/docs/#conformsTo
import { conformsTo } from 'lodash'
const object = { a: 1, b: 2 }
conformsTo(object, {
b: n => n > 1,
})
// => true
conformsTo(object, {
b: n => n > 2,
})
// => false
const conformsTo = (obj, ruleSet) =>
Object.keys(ruleSet).every(key => ruleSet[key](obj[key]))
const object = { a: 1, b: 2 }
conformsTo(object, {
b: n => n > 1,
})
// => true
conformsTo(object, {
b: n => n > 2,
})
// => false
Resources: Object.keys Array#every
Checks if value
is greater than other
.
// https://lodash.com/docs/#gt
import { gt } from 'lodash'
gt(3, 1)
// => true
gt(3, 3)
// => false
gt(1, 3)
// => false
const gt = (a, b) => a > b
gt(3, 1)
// => true
gt(3, 3)
// => false
gt(1, 3)
// => false
Resources: Comparison Operators
Checks if value
is greater than or equal to other
.
// https://lodash.com/docs/#gte
import { gte } from 'lodash'
gte(3, 1)
// => true
gte(3, 3)
// => true
gte(1, 3)
// => false
const gte = (a, b) => a >= b
gte(3, 1)
// => true
gte(3, 3)
// => true
gte(1, 3)
// => false
Resources: Comparison Operators
Checks if value
is classified as an Array
object.
// https://lodash.com/docs/#isArray
import { isArray } from 'lodash'
isArray([1, 2, 3])
// => true
isArray(document.body.children)
// => false
isArray('abc')
// => false
Array.isArray([1, 2, 3])
// => true
Array.isArray(document.body.children)
// => false
Array.isArray('abc')
// => false
Resources: Array.isArray
Checks if value
is an instance of ArrayBuffer
.
// https://lodash.com/docs/#isArrayBuffer
import { isArrayBuffer } from 'lodash'
isArrayBuffer(new ArrayBuffer(2))
// => true
isArrayBuffer(new Array(2))
// => false
// Since Node.js v10+, it's available in the util library
// https://nodejs.org/api/util.html##utiltypesisarraybuffervalue
//
// This implementation is a simplified version of the one found
// in the polyfill module node-util (and it doesn't support IE)
const isArrayBuffer = value => value.toString() === '[object ArrayBuffer]'
isArrayBuffer(new ArrayBuffer(2))
// => true
isArrayBuffer(new Array(2))
// => false
Resources: Node.js node-util
Checks if value
is array-like. A value is considered array-like if it’s not a function and has a value.length
that’s an integer greater than or equal to 0
and less than or equal to Number.MAX_SAFE_INTEGER
.
// https://lodash.com/docs/#isArrayLike
import { isArrayLike } from 'lodash'
isArrayLike([1, 2, 3])
// => true
isArrayLike(document.body.children)
// => true
isArrayLike('abc')
// => true
isArrayLike({ a: 1 })
// => false
isArrayLike(() => {})
// => false
const isArrayLike = a =>
typeof a !== 'function' &&
a?.length >= 0 &&
a?.length <= Number.MAX_SAFE_INTEGER
isArrayLike([1, 2, 3])
// => true
isArrayLike(document.body.children)
// => true
isArrayLike('abc')
// => true
isArrayLike({ a: 1 })
// => false
isArrayLike(() => {})
// => false
Resources: Number.MAX_SAFE_INTEGER Optional Chaining
Checks if value
is classified as a boolean primitive or object.
// https://lodash.com/docs/#isBoolean
import { isBoolean } from 'lodash'
isBoolean(false)
// => true
isBoolean(null)
// => false
const isBoolean = arg => arg === !!arg
isBoolean(false)
// => true
isBoolean(null)
// => false
Checks if value
is classified as a Date
object.
// https://lodash.com/docs/#isDate
import { isDate } from 'lodash'
isDate(new Date())
// => true
isDate('Mon April 23 2012')
// => false
const isDate = d => d instanceof Date && !isNaN(d)
isDate(new Date())
// => true
isDate('Mon April 23 2012')
// => false
Resources: instanceof
Checks if value
is an Error
, EvalError
, RangeError
, ReferenceError
, SyntaxError
, TypeError
, or URIError
object.
// https://lodash.com/docs/#isError
import { isError } from 'lodash'
isError(new Error())
// => true
isError(Error)
// => false
const isError = err => err instanceof Error
isError(new Error())
// => true
isError(Error)
// => false
Resources: instanceof
Checks if value
is a finite primitive number.
// https://lodash.com/docs/#isFinite
import { isFinite } from 'lodash'
isFinite(3)
// => true
isFinite(Number.MIN_VALUE)
// => true
isFinite(Infinity)
// => false
isFinite('3')
// => false
Number.isFinite(3)
// => true
Number.isFinite(Number.MIN_VALUE)
// => true
Number.isFinite(Infinity)
// => false
Number.isFinite('3')
// => false
Resources: Number.isFinite
Checks if value
is classified as a Function
object.
// https://lodash.com/docs/#isFunction
import { isFunction } from 'lodash'
isFunction(function () {})
// => true
isFunction(() => {})
// => true
isFunction(class NotAFunction {})
// => true
isFunction(/abc/)
// => false
const isFunction = val => typeof val === 'function'
isFunction(function () {})
// => true
isFunction(() => {})
// => true
isFunction(class NotAFunction {})
// => false
isFunction(/abc/)
// => false
Resources: typeof
Checks if value
is an integer.
// https://lodash.com/docs/#isInteger
import { isInteger } from 'lodash'
isInteger(3)
// => true
isInteger(Number.MIN_VALUE)
// => false
isInteger(Infinity)
// => false
isInteger('3')
// => false
Number.isInteger(3)
// => true
Number.isInteger(Number.MIN_VALUE)
// => false
Number.isInteger(Infinity)
// => false
Number.isInteger('3')
// => false
Resources: Number.isInteger
value
is classified as a Map
object.// https://lodash.com/docs/#isMap
import { isMap } from 'lodash'
isMap(new Map())
// => true
isMap(new WeakMap())
// => false
// Since Node.js v10+, it's available in the util library
// https://nodejs.org/api/util.html##util_util_types_ismap_value
//
// This implementation is a simplified version of the one found
// in the polyfill module node-util (and it doesn't support IE)
const isMap = value => value.toString() === '[object Map]'
isMap(new Map())
// => true
isMap(new WeakMap())
// => false
Performs a partial deep comparison between object
and source
to determine if object
contains equivalent property values.
// https://lodash.com/docs/#isMatch
import { isMatch } from 'lodash'
const object = { 'a': 1, 'b': 2, c: { a: 2 }, d: [1, 2, 3], e: {} }
isMatch(object, { 'b': 2 })
// => true
isMatch(object, { 'b': 1 })
// => false
isMatch(object, { 'c': { a: 2 } })
// => true
isMatch(object, { 'c': { a: 3 } })
// => false
isMatch(object, { 'd': [1, 2, 3] })
// => true
isMatch(object, { 'd': [2] })
// => true
isMatch(object, { 'd': 2 })
// => false
isMatch(object, { 'e': {} })
// => true
const isMatch = (object, source) => {
for (let key in source) {
// For arrays we look for partial matches
if (Array.isArray(source[key]) && Array.isArray(object[key])) {
return source[key].every(v => object[key].includes(v))
}
// For any other data type we look for equality of the values
return typeof source[key] === 'object'
? isMatch(object[key], source[key])
: object[key] === source[key]
}
// This should catch emtpy structures
return JSON.stringify(object) === JSON.stringify(source)
}
const object = { 'a': 1, 'b': 2, c: { a: 2 }, d: [1, 2, 3], e: {} }
isMatch(object, { 'b': 2 })
// => true
isMatch(object, { 'b': 1 })
// => false
isMatch(object, { 'c': { a: 2 } })
// => true
isMatch(object, { 'c': { a: 3 } })
// => false
isMatch(object, { 'd': [1, 2, 3] })
// => true
isMatch(object, { 'd': [2] })
// => true
isMatch(object, { 'd': 2 })
// => false
isMatch(object, { 'e': {} })
// => true
Resources: Array.isArray Array#every Array#includes
Checks if value
is NaN
.
// https://lodash.com/docs/#isNaN
import { isNaN } from 'lodash'
isNaN(NaN)
// => true
isNaN(Number(NaN))
// => true
isNaN(undefined)
// => false
Number.isNaN(NaN)
// => true
Number.isNaN(Number(NaN))
// => true
Number.isNaN(undefined)
// => false
Resources: Number.isNaN
Checks if value
is null
or undefined
.
// https://lodash.com/docs/#isNil
import { isNil } from 'lodash'
isNil(null)
// => true
isNil(undefined)
// => true
isNil(NaN)
// => false
const isNil = val => val == null
isNil(null)
// => true
isNil(undefined)
// => true
isNil(NaN)
// => false
Resources: Comparison Operators
Checks if value
is null
.
// https://lodash.com/docs/#isNull
import { isNull } from 'lodash'
isNull(null)
// => true
isNull(undefined)
// => false
const isNull = val => val === null
isNull(null)
// => true
isNull(undefined)
// => false
Resources: Equality comparisons
Checks if value
is classified as a Number
primitive or object.
// https://lodash.com/docs/#isNumber
import { isNumber } from 'lodash'
isNumber(3)
// => true
isNumber(Number.MIN_VALUE)
// => true
isNumber(Infinity)
// => true
isNumber('3')
// => false
const isNumber = a => typeof a === 'number'
isNumber(3)
// => true
isNumber(Number.MIN_VALUE)
// => true
isNumber(Infinity)
// => true
isNumber('3')
// => false
Resources: typeof
Checks if value
is the language type of Object
. (e.g. arrays, functions, objects, regexes, new Number(0)
, and new String(’’)
)
// https://lodash.com/docs/#isObject
import { isObject } from 'lodash'
isObject({})
// => true
isObject([1, 2, 3])
// => true
isObject(() => {})
// => true
isObject(null)
// => false
const isObject = a => a instanceof Object
isObject({})
// => true
isObject([1, 2, 3])
// => true
isObject(() => {})
// => true
isObject(null)
// => false
Resources: instanceof
Checks if value
is classified as a RegExp
object.
// https://lodash.com/docs/#isRegExp
import { isRegExp } from 'lodash'
isRegExp(/abc/)
// => true
isRegExp('/abc/')
// => false
const isRegExp = obj => obj instanceof RegExp
isRegExp(/abc/)
// => true
isRegExp('/abc/')
// => false
Resources: instanceof
Checks if value
is a safe integer. An integer is safe if it’s an IEEE-754 double precision number which isn’t the result of a rounded unsafe integer.
// https://lodash.com/docs/#isSafeInteger
import { isSafeInteger } from 'lodash'
isSafeInteger(3)
// => true
isSafeInteger(Number.MIN_VALUE)
// => false
isSafeInteger(Infinity)
// => false
isSafeInteger('3')
// => false
const isSafeInteger = n => Number.isSafeInteger(n)
isSafeInteger(3)
// => true
isSafeInteger(Number.MIN_VALUE)
// => false
isSafeInteger(Infinity)
// => false
isSafeInteger('3')
// => false
Resources: Number.isSafeInteger
Checks if value
is an instance of Set
.
// https://lodash.com/docs/#isSet
import { isSet } from 'lodash'
isSet(new Set())
// => true
isSet(new WeakSet())
// => false
// Since Node.js v10+, it's available in the util library
// https://nodejs.org/api/util.html##util_util_types_isset_value
//
// This implementation is a simplified version of the one found
// in the polyfill module node-util (and it doesn't support IE)
const isSet = value => value.toString() === '[object Set]'
isSet(new Set())
// => true
isSet(new WeakSet())
// => false
Resources: Node.js node-util
Checks if value
is classified as a String
primitive or object.
// https://lodash.com/docs/#isString
import { isString } from 'lodash'
isString('abc')
// => true
isString(1)
// => false
const isString = a => typeof a === 'string'
isString('abc')
// => true
isString(1)
// => false
Resources: typeof
Checks if value
is an instance of Symbol
.
// https://lodash.com/docs/#isSymbol
import { isSymbol } from 'lodash'
isSymbol(Symbol.iterator)
// => true
isSymbol('abc')
// => false
const isSymbol = symbolMaybe => typeof symbolMaybe === 'symbol'
isSymbol(Symbol.iterator)
// => true
isSymbol('abc')
// => false
Checks if value
is classified as a typed array.
import { isTypedArray } from 'util/types'
isTypedArray(new Uint8Array())
// => true
isTypedArray(new Float64Array())
// => true
isTypedArray(new ArrayBuffer())
// => false
// Since Node.js v10+, it's available in the util library
// https://nodejs.org/api/util.html#utiltypesistypedarrayvalue
//
// This implementation is a simplified version of the one found
// in underscore.js (and it doesn't support IE some early Edge versions)
// the Regex tests on whether the Object.toString of the array passed matches any
// typed array. I.e.: [object Int32Array] or [object Float64Array]
const typedArrayPattern =
/\[object ((I|Ui)nt(8|16|32)|Float(32|64)|Uint8Clamped|Big(I|Ui)nt64)Array\]/
const isTypedArray = value =>
typedArrayPattern.test(Object.prototype.toString.call(value))
isTypedArray(new Uint8Array())
// => true
isTypedArray(new Float64Array())
// => true
isTypedArray(new ArrayBuffer())
// => false
Resources: Node.js underscore.js
Checks if value
is undefined
.
// https://lodash.com/docs/#isUndefined
import { isUndefined } from 'lodash'
isUndefined(undefined)
// => true
isUndefined(null)
// => false
const isUndefined = val => val === undefined
isUndefined(undefined)
// => true
isUndefined(null)
// => false
Resources: Equality comparisons
Checks if value
is an instance of WeakMap
.
// https://lodash.com/docs/#isWeakMap
import { isWeakMap } from 'lodash'
isWeakMap(new WeakMap())
// => true
isWeakMap(new WeakSet())
// => false
// Since Node.js v10+, it's available in the util library
// https://nodejs.org/api/util.html##utiltypesisweakmapvalue
//
// This implementation is a simplified version of the one found
// in the polyfill module node-util (and it doesn't support IE)
const isWeakMap = value => value.toString() === '[object WeakMap]'
isWeakMap(new WeakMap())
// => true
isWeakMap(new WeakSet())
// => false
Resources: Node.js node-util
Checks if value
is an instance of WeakSet
.
// https://lodash.com/docs/#isWeakSet
import { isWeakSet } from 'lodash'
isWeakSet(new WeakSet())
// => true
isWeakSet(new WeakMap())
// => false
// Since Node.js v10+, it's available in the util library
// https://nodejs.org/api/util.html#utiltypesisweaksetvalue
//
// This implementation is a simplified version of the one found
// in the polyfill module node-util (and it doesn't support IE)
const isWeakSet = value => value.toString() === '[object WeakSet]'
isWeakSet(new WeakSet())
// => true
isWeakSet(new WeakMap())
// => false
Resources: Node.js node-util
Checks if value
is less than other
.
// https://lodash.com/docs/#lt
import { lt } from 'lodash'
lt(1, 3)
// => true
lt(3, 3)
// => false
lt(3, 1)
// => false
const lt = (a, b) => a < b
lt(1, 3)
// => true
lt(3, 3)
// => false
lt(3, 1)
// => false
Resources: Comparison Operators
Checks if value
is less than or equal to other
.
// https://lodash.com/docs/#lte
import { lte } from 'lodash'
lte(1, 3)
// => true
lte(3, 3)
// => true
lte(3, 1)
// => false
const lte = (a, b) => a <= b
lte(1, 3)
// => true
lte(3, 3)
// => false
lte(3, 1)
// => false
Resources: Comparison Operators
Adds two numbers.
// https://lodash.com/docs/#add
import { add } from 'lodash'
add(6, 4)
// => 10
const add = (a, b) => a + b
add(6, 4)
// => 10
Computes number
rounded up to precision
.
// https://lodash.com/docs/#ceil
import { ceil } from 'lodash'
ceil(4.006)
// => 5
ceil(6.004, 2)
// => 6.01
ceil(6040, -2)
// => 6100
const ceil = (num, precision) => {
const modifier = 10 ** precision
return Math.ceil(num * modifier) / modifier
}
Math.ceil(4.006)
// => 5
ceil(6.004, 2)
// => 6.01
ceil(6040, -2)
// => 6100
Resources: Assignment Operators
Divide two numbers.
// https://lodash.com/docs/#divide
import { divide } from 'lodash'
divide(6, 4)
// => 1.5
const divide = (a, b) => a / b
divide(6, 4)
// => 1.5
Computes number
rounded down to precision
.
// https://lodash.com/docs/#floor
import { floor } from 'lodash'
floor(4.006)
// => 4
floor(0.046, 2)
// => 0.04
floor(4060, -2)
// => 4000
const floor = (num, precision) => {
const modifier = 10 ** precision
return Math.floor(num * modifier) / modifier
}
Math.floor(4.006)
// => 4
floor(0.046, 2)
// => 0.04
floor(4060, -2)
// => 4000
Resources: Assignment Operators
Computes the maximum value of array
. If array
is empty or falsey, undefined
is returned.
// https://lodash.com/docs/#max
import { max } from 'lodash'
max([4, 2, 8, 6])
// => 8
max([])
// => undefined
const max = nums => {
if (nums.length) return Math.max(...nums)
}
max([4, 2, 8, 6])
// => 8
max([])
// => undefined
Resources: Spread syntax
This method is like _.max
except that it accepts iteratee
which is invoked for each element in array
to generate the criterion by which the value is ranked. The iteratee is invoked with one argument: (value).
// https://lodash.com/docs/#maxBy
import { maxBy } from 'lodash'
const objects = [{ n: 1 }, { n: 2 }]
maxBy(objects, o => o.n)
// => { 'n': 2 }
const maxBy = (arr, func) => {
const max = Math.max(...arr.map(func))
return arr.find(item => func(item) === max)
}
const objects = [{ n: 1 }, { n: 2 }]
maxBy(objects, o => o.n)
// => { 'n': 2 }
Resources: Spread syntax
Computes the mean of the values in array
.
// https://lodash.com/docs/#mean
import { mean } from 'lodash'
mean([4, 2, 8, 6])
// => 5
const mean = arr => arr.reduce((acc, num) => acc + num, 0) / arr.length
mean([4, 2, 8, 6])
// => 5
Resources: Array#reduce
This method is like _.mean
except that it accepts iteratee
which is invoked for each element in array
to generate the value to be averaged. The iteratee is invoked with one argument: (value).
// https://lodash.com/docs/#meanBy
import { meanBy } from 'lodash'
const objects = [{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }]
meanBy(objects, o => o.n)
// => 5
const meanBy = (arr, func) =>
arr.reduce((acc, item) => acc + func(item), 0) / arr.length
const objects = [{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }]
meanBy(objects, o => o.n)
// => 5
Resources: Array#reduce
Computes the minimum value of array
. If array
is empty or falsey, undefined
is returned.
// https://lodash.com/docs/#min
import { min } from 'lodash'
min([4, 2, 8, 6])
// => 2
min([])
// => undefined
const min = nums => {
if (nums.length) return Math.min(...nums)
}
min([4, 2, 8, 6])
// => 2
min([])
// => undefined
Resources: Spread syntax
This method is like _.min
except that it accepts iteratee
which is invoked for each element in array
to generate the criterion by which the value is ranked. The iteratee is invoked with one argument: (value).
// https://lodash.com/docs/#minBy
import { minBy } from 'lodash'
const objects = [{ n: 1 }, { n: 2 }]
minBy(objects, o => o.n)
// => { 'n': 1 }
const minBy = (arr, func) => {
const min = Math.min(...arr.map(func))
return arr.find(item => func(item) === min)
}
const objects = [{ n: 1 }, { n: 2 }]
minBy(objects, o => o.n)
// => { 'n': 1 }
Resources: Spread syntax
Multiply two numbers.
// https://lodash.com/docs/#multiply
import { multiply } from 'lodash'
multiply(6, 4)
// => 24
const multiply = (a, b) => a * b
multiply(6, 4)
// => 24
Computes number
rounded to precision
.
// https://lodash.com/docs/#round
import { round } from 'lodash'
round(4.006)
// => 4
round(4.006, 2)
// => 4.01
round(4060, -2)
// => 4100
const round = (num, precision) => {
const modifier = 10 ** precision
return Math.round(num * modifier) / modifier
}
Math.round(4.006)
// => 4
round(4.006, 2)
// => 4.01
round(4060, -2)
// => 4100
Resources: Assignment Operators
Subtract two numbers.
// https://lodash.com/docs/#subtract
import { subtract } from 'lodash'
subtract(6, 4)
// => 2
const subtract = (a, b) => a - b
subtract(6, 4)
// => 2
Computes the sum of the values in array
.
// https://lodash.com/docs/#sum
import { sum } from 'lodash'
sum([4, 2, 8, 6])
// => 20
[4, 2, 8, 6].reduce((acc, num) => {
acc += num
return acc
}, 0)
// => 20
Resources: Array#reduce
This method is like _.sum
except that it accepts iteratee
which is invoked for each element in array
to generate the value to be summed. The iteratee is invoked with one argument: (value).
// https://lodash.com/docs/#sumBy
import { sumBy } from 'lodash'
const objects = [{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }]
sumBy(objects, o => o.n)
// => 20
const sumBy = (arr, func) => arr.reduce((acc, item) => acc + func(item), 0)
const objects = [{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }]
sumBy(objects, o => o.n)
// => 20
Resources: Array#reduce
Clamps number
within the inclusive lower
and upper
bounds.
// https://lodash.com/docs/#clamp
import { clamp } from 'lodash'
clamp(-10, -5)
// => -10
clamp(-10, -5, 5)
// => -5
clamp(10, -5, 5)
// => 5
const clamp = (num, clamp, higher) =>
higher ? Math.min(Math.max(num, clamp), higher) : Math.min(num, clamp)
clamp(-10, -5)
// => -10
clamp(-10, -5, 5)
// => -5
clamp(10, -5, 5)
// => 5
Checks if n
is between start
and up to, but not including, end
. If end
is not specified, it’s set to start
with start
then set to 0
. If start
is greater than end
the params are swapped to support negative ranges.
// https://lodash.com/docs/#inRange
import { inRange } from 'lodash'
inRange(3, 2, 4)
// => true
inRange(4, 8)
// => true
inRange(4, 2)
// => false
inRange(2, 2)
// => false
inRange(1.2, 2)
// => true
inRange(5.2, 4)
// => false
inRange(-3, -2, -6)
// => true
const inRange = (num, rangeStart, rangeEnd = 0) =>
(rangeStart < num && num < rangeEnd) || (rangeEnd < num && num < rangeStart)
inRange(3, 2, 4)
// => true
inRange(4, 8)
// => true
inRange(4, 2)
// => false
inRange(2, 2)
// => false
inRange(1.2, 2)
// => true
inRange(5.2, 4)
// => false
inRange(-3, -2, -6)
// => true
Resources: Default parameters
Produces a random number between the inclusive lower
and upper
bounds. If only one argument is provided a number between 0
and the given number is returned. If floating
is true
, or either lower
or upper
are floats, a floating-point number is returned instead of an integer.
Note: JavaScript follows the IEEE-754 standard for resolving floating-point values which can produce unexpected results.
// https://lodash.com/docs/#random
import { random } from 'lodash'
random(0, 5)
// => an integer between 0 and 5
random(5)
// => also an integer between 0 and 5
random(5, true)
// => a floating-point number between 0 and 5
random(1.2, 5.2)
// => a floating-point number between 1.2 and 5.2
random()
// => 0 or 1
random(-1)
// => -1 or 0
const random = (lower = 0, upper, floating) => {
if (typeof upper === 'boolean') {
floating = upper
}
if (isNaN(upper)) {
upper = lower < 0 ? 0 : 1
}
if (typeof floating === 'undefined') {
floating = !Number.isInteger(lower) || !Number.isInteger(upper)
}
const randomNumber = Math.random() * (upper - lower) + lower
return floating ? randomNumber : Math.round(randomNumber)
}
random(0, 5)
// => an integer between 0 and 5
random(5)
// => also an integer between 0 and 5
random(5, true)
// => a floating-point number between 0 and 5
random(1.2, 5.2)
// => a floating-point number between 1.2 and 5.2
random()
// => 0 or 1
random(-1)
// => -1 or 0
Resources: Number.isInteger isNaN
Assigns own enumerable string keyed properties of source objects to the destination object. Source objects are applied from left to right. Subsequent sources overwrite property assignments of previous sources.
// https://lodash.com/docs/#assign
import { assign } from 'lodash'
function Foo() {
this.a = 1
}
function Bar() {
this.c = 3
}
Foo.prototype.b = 2
Bar.prototype.d = 4
assign({ a: 0 }, new Foo(), new Bar())
// => { 'a': 1, 'c': 3 }
function Foo() {
this.a = 1
}
function Bar() {
this.c = 3
}
Foo.prototype.b = 2
Bar.prototype.d = 4
{ a: 0, ...new Foo(), ...new Bar() }
// => { 'a': 1, 'c': 3 }
Resources: Spread syntax
Creates an object that inherits from the prototype
object. If a properties
object is given, its own enumerable string keyed properties are assigned to the created object.
// https://lodash.com/docs/#create
import { create } from 'lodash'
function Shape() {
this.x = 0
this.y = 0
}
function Circle() {
Shape.call(this)
}
Circle.prototype = create(Shape.prototype, {
constructor: Circle,
})
const circle = new Circle()
circle instanceof Circle
// => true
circle instanceof Shape
// => true
function Shape() {
this.x = 0
this.y = 0
}
function Circle() {
Shape.call(this)
}
Circle.prototype = Object.assign(Object.create(Shape.prototype), {
constructor: Circle,
})
const circle = new Circle()
circle instanceof Circle
// => true
circle instanceof Shape
// => true
Resources: Object.assign Object.create instanceof
Assigns own and inherited enumerable string keyed properties of source objects to the destination object for all destination properties that resolve to undefined
. Source objects are applied from left to right. Once a property is set, additional values of the same property are ignored.
// https://lodash.com/docs/#defaults
import { defaults } from 'lodash'
defaults({ a: 1 }, { b: 2 }, { a: 3 })
// // => { 'a': 1, 'b': 2 }
const defaults = (...args) =>
args.reverse().reduce((acc, obj) => ({ ...acc, ...obj }), {})
defaults({ a: 1 }, { b: 2 }, { a: 3 })
// // => { 'a': 1, 'b': 2 }
Resources: Spread syntax Array#reverse Array#reduce
Gets the value at path
of object
. If the resolved value is undefined
, the defaultValue
is returned in its place.
// https://lodash.com/docs/#get
import { get } from 'lodash'
const simpleObject = { a: { b: 2 } }
const complexObject = { a: [{ bar: { c: 3 } }] }
const falsyObject = { a: null, b: undefined, c: 0 }
get(simpleObject, 'a.b')
// => 2
get(complexObject, 'a[0].bar.c')
// => 3
get(complexObject, ['a', '0', 'bar', 'c'])
// => 2
get(simpleObject, 'a.bar.c', 'default')
// => 'default'
get(complexObject, 'a.bar.c', 'default')
// => 'default'
get(complexObject, null)
// => undefined
get(falsyObject, 'a', 'default')
// => null
get(falsyObject, 'b', 'default')
// => undefined
get(falsyObject, 'c', 'default')
// => zero
const get = (obj, path, defValue) => {
// If path is not defined or it has false value
if (!path) return undefined
// Check if path is string or array. Regex : ensure that we do not have '.' and brackets.
// Regex explained: https://regexr.com/58j0k
const pathArray = Array.isArray(path) ? path : path.match(/([^[.\]])+/g)
// Find value
const result = pathArray.reduce(
(prevObj, key) => prevObj && prevObj[key],
obj
)
// If found value is undefined return default value; otherwise return the value
return result === undefined ? defValue : result
}
const simpleObject = { a: { b: 2 } }
const complexObject = { a: [{ bar: { c: 3 } }] }
const falsyObject = { a: null, b: undefined, c: 0 }
get(simpleObject, 'a.b')
// => 2
get(complexObject, 'a[0].bar.c')
// => 3
get(complexObject, ['a', '0', 'bar', 'c'])
// => 2
get(simpleObject, 'a.bar.c', 'default')
// => 'default'
get(complexObject, 'a.bar.c', 'default')
// => 'default
get(complexObject, null)
// => undefined
get(falsyObject, 'a', 'default')
// => null
get(falsyObject, 'b', 'default')
// => undefined
get(falsyObject, 'c', 'default')
// => zero
Resources: Array.isArray Array#reduce Array#filter xkcd
Checks if path
is a direct property of object
.
// https://lodash.com/docs/#has
import { has } from 'lodash'
const object = { a: { bar: 2 } }
has(object, 'a')
// => true
has(object, 'a.bar')
// => true
has(object, ['a', 'bar'])
// => true
has(object, ['a', 'c'])
// => false
const has = (obj, path) => {
// Regex explained: https://regexr.com/58j0k
const pathArray = Array.isArray(path) ? path : path.match(/([^[.\]])+/g)
return !!pathArray.reduce((prevObj, key) => prevObj && prevObj[key], obj)
}
const object = { a: { bar: 2 } }
has(object, 'a')
// => true
has(object, 'a.bar')
// => true
has(object, ['a', 'bar'])
// => true
has(object, ['a', 'c'])
// => false
Resources: Array.isArray Array#reduce xkcd
Creates an object composed of the inverted keys and values of object
. If object
contains duplicate values, subsequent values overwrite property assignments of previous values.
// https://lodash.com/docs/#invert
import { invert } from 'lodash'
const object = { a: 1, b: 2, c: 1 }
invert(object)
// => { '1': 'c', '2': 'b' }
const object = { a: 1, b: 2, c: 1 }
Object.entries(object).reduce(
(acc, [key, value]) => ({
...acc,
[value]: key,
}),
{}
)
// => { '1': 'c', '2': 'b' }
Resources: Object.entries Spread syntax Array#reduce
Creates an array of the own enumerable property names of object
.
// https://lodash.com/docs/#keys
import { keys } from 'lodash'
function Foo() {
this.a = 1
this.b = 2
}
Foo.prototype.c = 3
keys(new Foo())
// => ['a', 'b'] (iteration order is not guaranteed)
keys('hi')
// => ['0', '1']
function Foo() {
this.a = 1
this.b = 2
}
Foo.prototype.c = 3
Object.keys(new Foo())
// => ['a', 'b'] (iteration order is not guaranteed)
Object.keys('hi')
// => ['0', '1']
Resources: Object.keys
The opposite of _.mapValues
; this method creates an object with the same values as object
and keys generated by running each own enumerable string keyed property of object
thru iteratee
. The iteratee is invoked with three arguments: (value, key, object).
// https://lodash.com/docs/#mapKeys
import { mapKeys } from 'lodash'
mapKeys({ a: 1, b: 2 }, (value, key) => key + value)
// => { 'a1': 1, 'b2': 2 }
const mapKeys = (obj, mapper) =>
Object.entries(obj).reduce(
(acc, [key, value]) => ({
...acc,
[mapper(value, key)]: value,
}),
{}
)
mapKeys({ a: 1, b: 2 }, (value, key) => key + value)
// => { 'a1': 1, 'b2': 2 }
Resources: Object.entries Array#reduce Spread syntax Computed property names
The opposite of _.pick
; this method creates an object composed of the own and inherited enumerable property paths of object
that are not omitted.
// https://lodash.com/docs/#omit
import { omit } from 'lodash'
const object = { a: 1, b: '2', c: 3 }
omit(object, ['a', 'c'])
// => { 'b': '2' }
const omit = (obj, props) => {
obj = { ...obj }
props.forEach(prop => delete obj[prop])
return obj
}
const object = { a: 1, b: '2', c: 3 }
omit(object, ['a', 'c'])
// => { 'b': '2' }
Resources: Spread syntax Array#forEach Delete operator
The opposite of _.pickBy
; this method creates an object composed of the own and inherited enumerable string keyed properties of object
that predicate
doesn’t return truthy for. The predicate is invoked with two arguments: (value, key).
// https://lodash.com/docs/#omitBy
import { omitBy, isNumber } from 'lodash'
const object = { a: 1, b: '2', c: 3 }
omitBy(object, isNumber)
// => { 'b': '2' }
const isNumber = a => typeof a === 'number'
const omitBy = (obj, check) => {
obj = { ...obj }
Object.entries(obj).forEach(([key, value]) => check(value) && delete obj[key])
return obj
}
const object = { a: 1, b: '2', c: 3 }
omitBy(object, isNumber)
// => { 'b': '2' }
Resources: Spread syntax Object.entries Array#forEach Delete operator
Creates an object composed of the picked object
properties.
// https://lodash.com/docs/#pick
import { pick } from 'lodash'
const object = {
a: 1,
b: 2,
c: 3,
}
pick(object, ['a', 'c'])
// => {a: 1, c: 3}
const object = {
a: 1,
b: 2,
c: 3,
}
const { a, c } = object
{ a, c }
// => {a: 1, c: 3}
Resources: Object destructuring
Sets the value at path
of object
. If a portion of path
doesn’t exist, it’s created. Arrays are created for missing index properties while objects are created for all other missing properties. Use _.setWith
to customize path
creation.
Note: This method mutates object
.
// https://lodash.com/docs/#set
import { set } from 'lodash'
const object = { a: [{ bar: { c: 3 } }] }
set(object, 'a[0].bar.c', 4)
object.a[0].bar.c
// => 4
set(object, ['x', '0', 'y', 'z'], 5)
object.x[0].y.z
// => 5
const set = (obj, path, value) => {
// Regex explained: https://regexr.com/58j0k
const pathArray = Array.isArray(path) ? path : path.match(/([^[.\]])+/g)
pathArray.reduce((acc, key, i) => {
if (acc[key] === undefined) acc[key] = {}
if (i === pathArray.length - 1) acc[key] = value
return acc[key]
}, obj)
}
const object = { a: [{ bar: { c: 3 } }] }
set(object, 'a[0].bar.c', 4)
object.a[0].bar.c
// => 4
set(object, ['x', '0', 'y', 'z'], 5)
object.x[0].y.z
// => 5
Resources: Array.isArray Array#reduce xkcd
Removes the property at path
of object
.
Note: This method mutates object
.
// https://lodash.com/docs/#unset
import { unset } from 'lodash'
const object = { a: [{ bar: { c: 7, d: 6 } }] }
unset(object, 'a[0].bar.c')
object
// => { 'a': [{ 'bar': { 'd': 6 } }] };
const unset = (obj, path) => {
// Regex explained: https://regexr.com/58j0k
const pathArray = Array.isArray(path) ? path : path.match(/([^[.\]])+/g)
pathArray.reduce((acc, key, i) => {
if (i === pathArray.length - 1) delete acc[key]
return acc[key]
}, obj)
}
const object = { a: [{ bar: { c: 7, d: 6 } }] }
unset(object, 'a[0].bar.c')
object
// => { 'a': [{ 'bar': { 'd': 6 } }] };
Resources: Array.isArray Array#reduce Delete operator xkcd
Creates an array of the own enumerable string keyed property values of object
.
// https://lodash.com/docs/#values
import { values } from 'lodash'
const object = {
0: {
a: 1,
b: 2,
c: 3,
},
1: {
d: 4,
e: 5,
f: 6,
},
}
values(object)
// => [{a: 1, b: 2, c: 3}, {d: 4, e: 5, f: 6}]
const object = {
0: {
a: 1,
b: 2,
c: 3,
},
1: {
d: 4,
e: 5,
f: 6,
},
}
Object.values(object)
// => [{a: 1, b: 2, c: 3}, {d: 4, e: 5, f: 6}]
Resources: Object.values
Converts the first character of string
to upper case and the remaining to lower case.
// https://lodash.com/docs/#capitalize
import { capitalize } from 'lodash'
capitalize('FRED')
// => 'Fred'
const capitalize = str =>
`${str.charAt(0).toUpperCase()}${str.slice(1).toLowerCase()}`
capitalize('FRED')
// => 'Fred'
Resources: String#charAt String#slice
Deburrs string
by converting Latin-1 Supplement and Latin Extended-A letters to basic Latin letters and removing combining diacritical marks.
// https://lodash.com/docs/#deburr
import { deburr } from 'lodash'
deburr('déjà vu')
// 'deja vu'
// prettier-ignore
const specialChars =['ä','æ','ö','œ','ü','Ä','Æ','Ü','Ö','Œ','À','Á','Â','Ã','Ä','Å','Ā','Ă','Ą','à','á','â','ã','å','ā','ă','ą','Ç','Ć','Ĉ','Ċ','Č','ç','ć','ĉ','ċ','č','Ð','Ď','Đ','ð','ď','đ','È','É','Ê','Ë','Ē','Ĕ','Ė','Ę','Ě','è','é','ê','ë','ē','ĕ','ė','ę','ě','Ĝ','Ğ','Ġ','Ģ','ĝ','ğ','ġ','ģ','Ĥ','Ħ','ĥ','ħ','Ì','Í','Î','Ï','Ĩ','Ī','Ĭ','Į','İ','ì','í','î','ï','ĩ','ī','ĭ','į','ı','Ĵ','ĵ','Ķ','ķ','ĸ','Ĺ','Ļ','Ľ','Ŀ','Ł','L','ĺ','ļ','ľ','ŀ','ł','Ñ','Ń','Ņ','Ň','Ŋ','ñ','ń','ņ','ň','ŋ','Ò','Ó','Ô','Õ','Ō','Ŏ','Ő','Ø','ò','ó','ô','õ','ō','ő','ø','Ŕ','Ŗ','Ř','ŕ','ŗ','ř','Ś','Ŝ','Ş','Š','ś','ŝ','ş','š','ſ','Ţ','Ť','Ŧ','ţ','ť','ŧ','Ù','Ú','Û','Ũ','Ū','Ŭ','Ů','Ű','Ų','ù','ú','û','ũ','ū','ŭ','ů','ű','ų','Ý','Ÿ','Ŷ','ý','ÿ','ŷ','Ŵ','ŵ','Ź','Ż','Ž','ź','ż','ž','Þ','þ','Æ','ß','IJ','ij']
specialChars.map(deburr)
// ['a','ae','o','oe','u','A','Ae','U','O','Oe','A','A','A','A','A','A','A','A','A','a','a','a','a','a','a','a','a','C','C','C','C','C','c','c','c','c','c','D','D','D','d','d','d','E','E','E','E','E','E','E','E','E','e','e','e','e','e','e','e','e','e','G','G','G','G','g','g','g','g','H','H','h','h','I','I','I','I','I','I','I','I','I','i','i','i','i','i','i','i','i','i','J','j','K','k','k','L','L','L','L','L','L','l','l','l','l','l','N','N','N','N','N','n','n','n','n','n','O','O','O','O','O','O','O','O','o','o','o','o','o','o','o','R','R','R','r','r','r','S','S','S','S','s','s','s','s','s','T','T','T','t','t','t','U','U','U','U','U','U','U','U','U','u','u','u','u','u','u','u','u','u','Y','Y','Y','y','y','y','W','w','Z','Z','Z','z','z','z','Th','th','Ae','ss','IJ','ij']
const deburr = str => str.normalize('NFD').replace(/\p{Diacritic}/gu, '')
deburr('déjà vu')
// 'deja vu'
// String#normalize only supports a subset of the _.deburr conversions.
// For more information have a look at the documentation on MDN:
// https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/normalize
//
// You might be fine with the out of the box support but this implementation
// also covers adding a range of extra characters.
//
// DISCLAIMER: the list presented might not be comprehensive!
const charMap = {
'oe': 'œ',
'ae': 'æ',
'Ae': 'Æ',
'Oe': 'Œ',
'D': 'Ð|D|Đ',
'd': 'ð|d|đ',
'H': 'Ħ',
'h': 'ħ',
'I': 'İ',
'i': 'ı',
'k': 'ĸ',
'L': 'Ŀ|Ł',
'l': 'ŀ|ł',
'N': 'Ŋ',
'n': 'ŋ',
'O': 'Ø',
'o': 'ø',
's': 'ſ',
'T': 'Ŧ',
't': 'ŧ',
'Th': 'Þ',
'th': 'þ',
'ss': 'ß',
'IJ': 'IJ',
'ij': 'ij',
}
const removeExtraChars = str =>
Object.entries(charMap).reduce((str, [normalised, specialChar]) => {
var re = new RegExp(specialChar, 'g')
return str.replace(re, normalised)
}, str)
const extendedDeburr = str => removeExtraChars(deburr(str))
// prettier-ignore
const specialChars =['ä','æ','ö','œ','ü','Ä','Æ','Ü','Ö','Œ','À','Á','Â','Ã','Ä','Å','Ā','Ă','Ą','à','á','â','ã','å','ā','ă','ą','Ç','Ć','Ĉ','Ċ','Č','ç','ć','ĉ','ċ','č','Ð','Ď','Đ','ð','ď','đ','È','É','Ê','Ë','Ē','Ĕ','Ė','Ę','Ě','è','é','ê','ë','ē','ĕ','ė','ę','ě','Ĝ','Ğ','Ġ','Ģ','ĝ','ğ','ġ','ģ','Ĥ','Ħ','ĥ','ħ','Ì','Í','Î','Ï','Ĩ','Ī','Ĭ','Į','İ','ì','í','î','ï','ĩ','ī','ĭ','į','ı','Ĵ','ĵ','Ķ','ķ','ĸ','Ĺ','Ļ','Ľ','Ŀ','Ł','L','ĺ','ļ','ľ','ŀ','ł','Ñ','Ń','Ņ','Ň','Ŋ','ñ','ń','ņ','ň','ŋ','Ò','Ó','Ô','Õ','Ō','Ŏ','Ő','Ø','ò','ó','ô','õ','ō','ő','ø','Ŕ','Ŗ','Ř','ŕ','ŗ','ř','Ś','Ŝ','Ş','Š','ś','ŝ','ş','š','ſ','Ţ','Ť','Ŧ','ţ','ť','ŧ','Ù','Ú','Û','Ũ','Ū','Ŭ','Ů','Ű','Ų','ù','ú','û','ũ','ū','ŭ','ů','ű','ų','Ý','Ÿ','Ŷ','ý','ÿ','ŷ','Ŵ','ŵ','Ź','Ż','Ž','ź','ż','ž','Þ','þ','Æ','ß','IJ','ij']
specialChars.map(extendedDeburr)
// ['a','ae','o','oe','u','A','Ae','U','O','Oe','A','A','A','A','A','A','A','A','A','a','a','a','a','a','a','a','a','C','C','C','C','C','c','c','c','c','c','D','D','D','d','d','d','E','E','E','E','E','E','E','E','E','e','e','e','e','e','e','e','e','e','G','G','G','G','g','g','g','g','H','H','h','h','I','I','I','I','I','I','I','I','I','i','i','i','i','i','i','i','i','i','J','j','K','k','k','L','L','L','L','L','L','l','l','l','l','l','N','N','N','N','N','n','n','n','n','n','O','O','O','O','O','O','O','O','o','o','o','o','o','o','o','R','R','R','r','r','r','S','S','S','S','s','s','s','s','s','T','T','T','t','t','t','U','U','U','U','U','U','U','U','U','u','u','u','u','u','u','u','u','u','Y','Y','Y','y','y','y','W','w','Z','Z','Z','z','z','z','Th','th','Ae','ss','IJ','ij']
Resources: Source Extended Version Source String#normalize Unicode property escapes Object.entries Array#reduce
Checks if string
ends with the given target string.
// https://lodash.com/docs/#endsWith
import { endsWith } from 'lodash'
endsWith('pinecone', 'cone')
// => true
Converts the characters “&”, “<”, “>”, ‘"’, and “’” in string
to their corresponding HTML entities.
Note: No other characters are escaped.
// https://lodash.com/docs/#escape
import { escape } from 'lodash'
escape('fred, barney, & pebbles')
// => 'fred, barney, & pebbles'
const escape = str => {
const map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": ''',
}
return str.replace(/[&<>"']/g, m => map[m])
}
escape('fred, barney, & pebbles')
// => 'fred, barney, & pebbles'
Resources: String#replace
Converts string
to kebab case.
// https://lodash.com/docs/#kebabCase
import { kebabCase } from 'lodash'
kebabCase('Foo Bar')
// => 'foo-bar'
kebabCase('fooBar')
// => 'foo-bar'
kebabCase('__FOO_BAR__')
// => 'foo-bar'
kebabCase(null)
// => ''
kebabCase('UPPERCASE')
// => 'uppercase'
kebabCase(false)
// => 'false'
kebabCase(undefined)
// => ''
kebabCase(0)
// => '0'
kebabCase('camelCase')
// => 'camel-case'
kebabCase('?')
// => ''
kebabCase('Custom*XML*Parser')
// => 'custom-xml-parser'
kebabCase('APIFinder')
// => 'api-finder'
kebabCase('UserAPI20Endpoint')
// => 'user-api-20-endpoint'
kebabCase('30fghIJ')
// => '30-fgh-ij'
// Regex explained: https://regexr.com/5c55v
const re = /([0-9]+|([A-Z][a-z]+)|[a-z]+|([A-Z]+)(?![a-z]))/g
const kebabCase = str =>
(String(str ?? '').match(re) || []).map(x => x.toLowerCase()).join('-')
kebabCase('Foo Bar')
// => 'foo-bar'
kebabCase('fooBar')
// => 'foo-bar'
kebabCase('__FOO_BAR__')
// => 'foo-bar'
kebabCase(null)
// => ''
kebabCase('UPPERCASE')
// => 'uppercase'
kebabCase(false)
// => 'false'
kebabCase(undefined)
// => ''
kebabCase(0)
// => '0'
kebabCase('camelCase')
// => 'camel-case'
kebabCase('?')
// => ''
kebabCase('Custom*XML*Parser')
// => 'custom-xml-parser'
kebabCase('APIFinder')
// => 'api-finder'
kebabCase('UserAPI20Endpoint')
// => 'user-api-20-endpoint'
kebabCase('30fghIJ')
// => '30-fgh-ij'
Resources: Nullish coalescing operator (??) Array#map Array#join String
Converts the first character of string
to lower case.
// https://lodash.com/docs/#lowerFirst
import { lowerFirst } from 'lodash'
lowerFirst('Fred')
// => 'fred'
lowerFirst('FRED')
// => 'fRED'
const lowerFirst = str => `${str.charAt(0).toLowerCase()}${str.slice(1)}`
lowerFirst('Fred')
// => 'fred'
lowerFirst('FRED')
// => 'fRED'
Resources: String#charAt String#slice
Pads string
on the left and right sides if it’s shorter than length
. Padding characters are truncated if they can’t be evenly divided by length
.
// https://lodash.com/docs/#pad
import { pad } from 'lodash'
pad('abc', 8)
// // => ' abc '
//
pad('abc', 8, '_-')
// // => '_-abc_-_'
//
pad('abc', 3)
// // => 'abc'
const pad = (str, pad, custom) => {
const prePad = Math.floor((pad - str.length) / 2) + str.length
return str.padStart(prePad, custom).padEnd(pad, custom)
}
pad('abc', 8)
// // => ' abc '
//
pad('abc', 8, '_-')
// // => '_-abc_-_'
//
pad('abc', 3)
// // => 'abc'
Resources: String#padStart String#padEnd
Pads string
on the right side if it’s shorter than length
. Padding characters are truncated if they exceed length
.
// https://lodash.com/docs/#padEnd
import { padEnd } from 'lodash'
padEnd('abc', 6)
// => 'abc '
padEnd('abc', 6, '_-')
// => 'abc_-_'
padEnd('abc', 3)
// => 'abc'
'abc'.padEnd(6)
// => 'abc '
'abc'.padEnd(6, '_-')
// => 'abc_-_'
'abc'.padEnd(3)
// => 'abc'
Resources: String#padEnd
Pads string
on the left side if it’s shorter than length
. Padding characters are truncated if they exceed length
.
// https://lodash.com/docs/#padStart
import { padStart } from 'lodash'
padStart('abc', 6)
// => ' abc'
padStart('abc', 6, '_-')
// => '_-_abc'
padStart('abc', 3)
// => 'abc'
'abc'.padStart(6)
// => ' abc'
'abc'.padStart(6, '_-')
// => '_-_abc'
'abc'.padStart(3)
// => 'abc'
Resources: String#padStart
Converts string
to an integer of the specified radix.
// https://lodash.com/docs/#parseInt
import { parseInt } from 'lodash'
parseInt('08')
// => 8
['6', '08', '10'].map(parseInt)
// => [6, 8, 10]
parseInt('08', 10)
// => 8
['6', '08', '10'].map(i => parseInt(i, 10))
// => [6, 8, 10]
Resources: parseInt
Repeats the given string n
times.
// https://lodash.com/docs/#repeat
import { repeat } from 'lodash'
repeat('*', 3)
// => '***'
repeat('abc', 2)
// => 'abcabc'
repeat('abc', 0)
// => ''
'*'.repeat(3)
// => '***'
'abc'.repeat(2)
// => 'abcabc'
'abc'.repeat(0)
// => ''
Resources: String#repeat
Replaces matches for pattern
in string
with replacement
.
// https://lodash.com/docs/#replace
import { replace } from 'lodash'
replace('Hi Fred', 'Fred', 'Barney')
// => 'Hi Barney'
const replace = (str, s, r) => str.replace(s, r)
replace('Hi Fred', 'Fred', 'Barney')
// => 'Hi Barney'
Resources: String#replace
Splits string
by separator
.
// https://lodash.com/docs/#split
import { split } from 'lodash'
split('a-b-c', '-')
// => ['a', 'b', 'c']
split('a-b-c', '-', 2)
// => ['a', 'b']
split('foo👨👨👧👦', '')
// => ['f', 'o', 'o', '👨👨👧👦']
'a-b-c'.split('-')
// => ['a', 'b', 'c']
'a-b-c'.split('-').slice(0, 2)
// => ['a', 'b']
// When the split is used with the empty separator, `String#split` and `_.split`
// will have the different behavior:
//
// `_.split` with empty string as a separator takes user-perceived characters
// (grapheme clusters) and unicode characters (codepoints) into account;
//
// `String#split` with empty string as a separator does not take them into
// account and will return string split by UTF-16 codeunits, which will destroy
// the surrogate pairs.
//
// To avoid this issue, `Intl.Segmenter` API could be used
//
// Please note that it is not yet supported in Firefox
Array.from(new Intl.Segmenter().segment('foo👨👨👧👦')).map(
({ segment }) => segment
)
// => ['f', 'o', 'o', '👨👨👧👦']
Resources: String#split
Intl.Segmenter
Intl Segmenter Polyfill
Checks if string
starts with the given target string.
// https://lodash.com/docs/#startsWith
import { startsWith } from 'lodash'
startsWith('JavaScript', 'Java')
// => true
Converts string
, as a whole, to lower case.
// https://lodash.com/docs/#toLower
import { toLower } from 'lodash'
toLower('--Foo-Bar--')
// => '--foo-bar--'
toLower('fooBar')
// => 'foobar'
toLower('__FOO_BAR__')
// => '__foo_bar__'
const toLower = str => str.toLowerCase()
toLower('--foo-bar--')
// => '--foo-bar--'
toLower('fooBar')
// => 'foobar'
toLower('__foo_bar__')
// => '__foo_bar__'
string
, as a whole, to upper case just like String#toUpperCase.// https://lodash.com/docs/#toUpper
import { toUpper } from 'lodash'
toUpper('--foo-bar--')
// => '--FOO-BAR--'
toUpper('fooBar')
// => 'FOOBAR'
toUpper('__foo_bar__')
// => '__FOO_BAR__'
const toUpper = str => str.toUpperCase()
toUpper('--foo-bar--')
// => '--FOO-BAR--'
toUpper('fooBar')
// => 'FOOBAR'
toUpper('__foo_bar__')
// => '__FOO_BAR__'
Removes leading and trailing whitespace or specified characters from string
.
// https://lodash.com/docs/#trim
import { trim } from 'lodash'
trim(' abc ')
// => 'abc'
trim('-_-abc-_-', '_-')
// => 'abc'
[' foo ', ' bar '].map(trim)
// => ['foo', 'bar']
// Regex explained: https://regexr.com/4v6jg
const trim = (str, c = '\\s') =>
str.replace(new RegExp(`^([${c}]*)(.*?)([${c}]*)$`), '$2')
' abc '.trim()
// => 'abc'
trim('-_-abc-_-', '_-')
// => 'abc'
[' foo ', ' bar '].map(s => trim(s))
// => ['foo', 'bar']
Resources: xkcd
Removes trailing whitespace or specified characters from string
.
// https://lodash.com/docs/#trimEnd
import { trimEnd } from 'lodash'
trimEnd(' abc ')
// => ' abc'
trimEnd('-_-abc-_-', '_-')
// => '-_-abc'
// Regex explained: https://regexr.com/4v6iu
const trimEnd = (str, c = '\\s') =>
str.replace(new RegExp(`^(.*?)([${c}]*)$`), '$1')
' abc '.trimEnd()
// => ' abc'
trimEnd(' abc ')
// => ' abc'
trimEnd('-_-abc-_-', '_-')
// => '-_-abc'
Resources: xkcd
Removes leading whitespace or specified characters from string
.
// https://lodash.com/docs/#trimStart
import { trimStart } from 'lodash'
trimStart(' abc ')
// => 'abc '
trimStart('-_-abc-_-', '_-')
// => 'abc-_-'
// Regex explained: https://regexr.com/4v6j7
const trimStart = (str, c = '\\s') =>
str.replace(new RegExp(`^([${c}]*)(.*)$`), '$2')
' abc '.trimStart()
// => 'abc '
trimStart(' abc ')
// => 'abc '
trimStart('-_-abc-_-', '_-')
// => 'abc-_-'
Resources: xkcd
Converts the first character of string
to upper case.
// https://lodash.com/docs/#upperFirst
import { upperFirst } from 'lodash'
upperFirst('fred')
// => 'Fred'
upperFirst('FRED')
// => 'FRED'
const upperFirst = str => `${str.charAt(0).toUpperCase()}${str.slice(1)}`
upperFirst('fred')
// => 'Fred'
upperFirst('FRED')
// => 'FRED'
Resources: String#charAt String#slice
Attempts to invoke func
, returning either the result or the caught error object. Any additional arguments are provided to func
when it’s invoked.
// https://lodash.com/docs/#attempt
import { attempt } from 'lodash'
attempt(item => item.split(''), 'string')
// => ["s", "t", "r", "i", "n", "g"]
attempt(item => item.split(''), 1)
// => [TypeError: item.split is not a function]
const attempt = (func, ...args) => {
try {
return func(...args)
} catch (e) {
return e
}
}
attempt(item => item.split(''), 'string')
// => ["s", "t", "r", "i", "n", "g"]
attempt(item => item.split(''), 1)
// => [TypeError: item.split is not a function]
Resources: Spread syntax try…catch
Creates a function that iterates over pairs
and invokes the corresponding function of the first predicate to return truthy. The predicate-function pairs
are invoked with the arguments of the created function.
// https://lodash.com/docs/#cond
import { cond, conforms, constant, isNumber, matches, stubTrue } from 'lodash'
var func = cond([
[matches({ 'a': 1 }), constant('matches A')],
[conforms({ 'b': isNumber }), constant('matches B')],
[stubTrue, constant('no match')],
])
func({ 'a': 1, 'b': 2 })
// => 'matches A'
func({ 'a': 0, 'b': 1 })
// => 'matches B'
func({ 'a': '1', 'b': '2' })
// => 'no match'
const multiArgCondition = cond([
[(x, y) => x > y, (x, y) => x - y * 2],
[() => true, (x, y) => y - x],
])
multiArgCondition(0, 5)
// => (y - x) === (5 - 0) === 5
multiArgCondition(2, 1)
// => (x - y * 2 ) === (2 - 2) === 0
multiArgCondition(2, 2)
// => (y - x) === (2 - 2) === 0
const cond =
pairs =>
(...item) => {
for (const [predicate, fn] of pairs) {
if (predicate(...item)) {
return fn(...item)
}
}
}
var func = cond([
[i => i.a === 1, () => 'matches A'],
[i => i.b === Number(i.b), () => 'matches B'],
[() => true, () => 'no match'],
])
func({ 'a': 1, 'b': 2 })
// => 'matches A'
func({ 'a': 0, 'b': 1 })
// => 'matches B'
func({ 'a': '1', 'b': '2' })
// => 'no match'
const multiArgCondition = cond([
[(x, y) => x > y, (x, y) => x - y * 2],
[() => true, (x, y) => y - x],
])
multiArgCondition(0, 5)
// => (y - x) === (5 - 0) === 5
multiArgCondition(2, 1)
// => (x - y * 2) === (2 - 2) === 0
multiArgCondition(2, 2)
// => (y - x) === (2 - 2) === 0
Resources: for…of
Resources: Destructuring_assignment
Creates a function that returns value
.
// https://lodash.com/docs/#constant
import { constant } from 'lodash'
const return42 = constant(42)
return42()
// => 42
const constant = arg => () => arg
const return42 = constant(42)
return42()
// => 42
Checks value
to determine whether a default value should be returned in its place. The defaultValue
is returned if value
is NaN
, null
, or undefined
.
// https://lodash.com/docs/#defaultTo
import { defaultTo } from 'lodash'
defaultTo(1, 10)
// => 1
defaultTo('', 10)
// => ''
defaultTo(undefined, 10)
defaultTo(null, 10)
defaultTo(NaN, 10)
// => 10
const defaultTo = (a, b) => (a == null || Object.is(a, NaN) ? b : a)
defaultTo(1, 10)
// => 1
defaultTo('', 10)
// => ''
defaultTo(undefined, 10)
defaultTo(null, 10)
defaultTo(NaN, 10)
// => 10
Resources: Object.is
Creates a function that returns the result of invoking the given functions with the this
binding of the created function, where each successive invocation is supplied the return value of the previous.
// https://lodash.com/docs/#flow
import { flow } from 'lodash'
const add = (a, b) => a + b
const square = n => n * n
const addSquare = flow([add, square])
addSquare(1, 2)
// => 9
const flow =
funcs =>
(...args) =>
funcs.reduce((prev, fnc) => [fnc(...prev)], args)[0]
const add = (a, b) => a + b
const square = n => n * n
const addSquare = flow([add, square])
addSquare(1, 2)
// => 9
Resources: Spread syntax Array#reduce
This method is like _.flow
except that it creates a function that invokes the given functions from right to left.
// https://lodash.com/docs/#flowRight
import { flowRight } from 'lodash'
function add(a, b) {
return a + b
}
function square(n) {
return n * n
}
const addSquare = flowRight([square, add])
addSquare(1, 2)
// => 9
const flowRight =
funcs =>
(...args) =>
funcs.reverse().reduce((prev, fnc) => [fnc(...prev)], args)[0]
const add = (a, b) => a + b
const square = n => n * n
const addSquare = flowRight([square, add])
addSquare(1, 2)
// => 9
Resources: Spread syntax Array#reduce
This method returns the first argument it receives.
// https://lodash.com/docs/#identity
import { identity } from 'lodash'
const object = { a: 1 }
identity(object) === object
// => true
const identity = a => a
const object = { a: 1 }
identity(object) === object
// => true
This method returns undefined
.
// https://lodash.com/docs/#noop
import { noop } from 'lodash'
noop()
// => undefined
const noop = () => {}
noop()
// => undefined
Creates a function that gets the argument at index n
. If n
is negative, the nth argument from the end is returned.
// https://lodash.com/docs/#nthArg
import { nthArg } from 'lodash'
let func = nthArg(1)
func('a', 'b', 'c', 'd')
// => 'b'
func = nthArg(-2)
func('a', 'b', 'c', 'd')
// => 'c'
const nthArg =
idx =>
(...args) =>
args.slice(idx, idx + 1)[0]
let func = nthArg(1)
func('a', 'b', 'c', 'd')
// => 'b'
func = nthArg(-2)
func('a', 'b', 'c', 'd')
// => 'c'
Resources: Spread syntax Array#slice
Creates a function that invokes iteratees
with the arguments it receives and returns their results.
// https://lodash.com/docs/#over
import { over } from 'lodash'
const func = over([Math.max, Math.min])
func(1, 2, 3, 4)
// => [4, 1]
const over =
arr =>
(...args) =>
arr.map(func => func(...args))
const func = over([Math.max, Math.min])
func(1, 2, 3, 4)
// => [4, 1]
Resources: Spread syntax Array#map
Creates a function that checks if all of the predicates
return truthy when invoked with the arguments it receives.
// https://lodash.com/docs/#overEvery
import { overEvery } from 'lodash'
const func = overEvery([Boolean, isFinite])
func('1')
// => true
func(null)
// => false
func(NaN)
// => false
const overSome = checks => item => checks.every(check => check(item))
const func = overSome([Boolean, isFinite])
func('1')
// => true
func(null)
// => false
func(NaN)
// => false
Resources: Array#every
Creates a function that checks if any of the predicates
return truthy when invoked with the arguments it receives.
// https://lodash.com/docs/#overSome
import { overSome } from 'lodash'
const func = overSome([Boolean, isFinite])
func('1')
// => true
func(null)
// => true
func(NaN)
// => false
const overSome = checks => item => checks.some(check => check(item))
const func = overSome([Boolean, isFinite])
func('1')
// => true
func(null)
// => true
func(NaN)
// => false
Resources: Array#some
Creates an array of numbers (positive and/or negative) progressing from start
up to, but not including, end
. A step of -1
is used if a negative start
is specified without an end
or step
. If end
is not specified, it’s set to start
with start
then set to 0
.
// https://lodash.com/docs/#range
import { range } from 'lodash'
range(4)
// => [0, 1, 2, 3]
range(-4)
// => [0, -1, -2, -3]
range(1, 5)
// => [1, 2, 3, 4]
range(0, 20, 5)
// => [0, 5, 10, 15]
range(0, -4, -1)
// => [0, -1, -2, -3]
range(1, 4, 0)
// => [1, 1, 1]
range(0)
// => []
const range = (start, end, increment) => {
// if the end is not defined...
const isEndDef = typeof end !== 'undefined'
// ...the first argument should be the end of the range...
end = isEndDef ? end : start
// ...and 0 should be the start
start = isEndDef ? start : 0
// if the increment is not defined, we could need a +1 or -1
// depending on whether we are going up or down
if (typeof increment === 'undefined') {
increment = Math.sign(end - start)
}
// calculating the lenght of the array, which has always to be positive
const length = Math.abs((end - start) / (increment || 1))
// In order to return the right result, we need to create a new array
// with the calculated length and fill it with the items starting from
// the start value + the value of increment.
const { result } = Array.from({ length }).reduce(
({ result, current }) => ({
// append the current value to the result array
result: [...result, current],
// adding the increment to the current item
// to be used in the next iteration
current: current + increment,
}),
{ current: start, result: [] }
)
return result
}
range(4)
// => [0, 1, 2, 3]
range(-4)
// => [0, -1, -2, -3]
range(1, 5)
// => [1, 2, 3, 4]
range(0, 20, 5)
// => [0, 5, 10, 15]
range(0, -4, -1)
// => [0, -1, -2, -3]
range(1, 4, 0)
// => [1, 1, 1]
range(0)
// => []
Resources: Array.from Array#reduce Spread syntax Math.abs Math.sign typeof
This method is like _.range
except that it populates values in descending order.
// https://lodash.com/docs/#rangeRight
import { rangeRight } from 'lodash'
rangeRight(4)
// => [3, 2, 1, 0]
rangeRight(-4)
// => [-3, -2, -1, 0]
rangeRight(1, 5)
// => [4, 3, 2, 1]
rangeRight(0, 20, 5)
// => [15, 10, 5, 0]
rangeRight(0, -4, -1)
// => [-3, -2, -1, 0]
rangeRight(1, 4, 0)
// => [1, 1, 1]
rangeRight(0)
// => []
const rangeRight = (start, end, increment) => {
// if the end is not defined...
const isEndDef = typeof end !== 'undefined'
// ...the first argument should be the end of the range...
end = isEndDef ? end : start
// ...and 0 should be the start
start = isEndDef ? start : 0
// if the increment is not defined, we could need a +1 or -1
// depending on whether we are going up or down
if (typeof increment === 'undefined') {
increment = Math.sign(end - start)
}
// calculating the lenght of the array, which has always to be positive
const length = Math.abs((end - start) / (increment || 1))
// In order to return the right result, we need to create a new array
// with the calculated length and fill it with the items starting from
// the start value + the value of increment.
const { result } = Array.from({ length }).reduce(
({ result, current }) => ({
// prepend the current value to the result array
result: [current, ...result],
// adding the increment to the current item
// to be used in the next iteration
current: current + increment,
}),
{ current: start, result: [] }
)
return result
}
rangeRight(4)
// => [3, 2, 1, 0]
rangeRight(-4)
// => [-3, -2, -1, 0]
rangeRight(1, 5)
// => [4, 3, 2, 1]
rangeRight(0, 20, 5)
// => [15, 10, 5, 0]
rangeRight(0, -4, -1)
// => [-3, -2, -1, 0]
rangeRight(1, 4, 0)
// => [1, 1, 1]
rangeRight(0)
// => []
Resources: Array.from Array#reduce Spread syntax Math.abs Math.sign typeof
This method returns a new empty array.
// https://lodash.com/docs/#stubArray
import { stubArray } from 'lodash'
stubArray()
// => []
const stubArray = () => []
stubArray()
// => []
This method returns false
.
// https://lodash.com/docs/#stubFalse
import { stubFalse } from 'lodash'
stubFalse()
// => false
const stubFalse = () => false
stubFalse()
// => false
This method returns a new empty object.
// https://lodash.com/docs/#stubObject
import { stubObject } from 'lodash'
stubObject()
// => {}
const stubObject = () => ({})
stubObject()
// => {}
This method returns an empty string.
// https://lodash.com/docs/#stubString
import { stubString } from 'lodash'
stubString()
// => ''
const stubString = () => ''
stubString()
// => ''
This method returns true
.
// https://lodash.com/docs/#stubTrue
import { stubTrue } from 'lodash'
stubTrue()
// => true
const stubTrue = () => true
stubTrue()
// => true
Invokes the iteratee n
times, returning an array of the results of each invocation. The iteratee is invoked with one argument; (index).
// https://lodash.com/docs/#times
import { times } from 'lodash'
times(3)
// => [0, 1, 2]
times(3, i => i + 3)
// => [3, 4, 5]
const times = (n, func = i => i) =>
Array.from({ length: n }).map((_, i) => func(i))
times(3)
// => [0, 1, 2]
times(3, i => i + 3)
// => [3, 4, 5]
Resources: Array.from Array#map
value
to a property path array.// https://lodash.com/docs/#toPath
import { toPath } from 'lodash'
toPath('a.b.c')
// => ['a', 'b', 'c']
toPath('a[0].b.c')
// => ['a', '0', 'b', 'c']
// Regex explained: https://regexr.com/58j0k
const toPath = path => path.match(/([^[.\]])+/g)
toPath('a.b.c')
// => ['a', 'b', 'c']
toPath('a[0].b.c')
// => ['a', '0', 'b', 'c']
Generates a unique ID. If prefix
is given, the ID is appended to it.
// https://lodash.com/docs/#uniqueId
import { uniqueId } from 'lodash'
uniqueId('contact_')
// => 'contact_1'
uniqueId()
// => '2'
const uniqueId = (
counter =>
(str = '') =>
`${str}${++counter}`
)(0)
uniqueId('contact_')
// => 'contact_1'
uniqueId()
// => '2'
Resources: IIFE