YOU MIGHT NOT NEED LODASH

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.

array

chunk

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.

lodash

// 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)
// => []

plain js

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

compact

Creates an array with all falsey values removed. The values false, null, 0, "", undefined, and NaN are falsey.

lodash

// https://lodash.com/docs/#compact
import { compact } from 'lodash'

compact([0, 1, 2])
// => [1, 2]

plain js

[0, 1, 2].filter(x => !!x)
// => [1, 2]
Resources: Array#filter Source

concat

Creates a new array concatenating array with any additional arrays and/or values.

lodash

// https://lodash.com/docs/#concat
import { concat } from 'lodash'

concat([1], 2, [3], [[4]])
// => [1, 2, 3, [4]]

plain js

[1].concat(2, [3], [[4]])
// => [1, 2, 3, [4]]
Resources: Array#concat Source

difference

Creates an array of array values not included in the other given arrays.

lodash

// https://lodash.com/docs/#difference
import { difference } from 'lodash'

difference([2, 1], [3, 2])
// => [1]

plain js

const difference = (arr1, arr2) => arr1.filter(x => !arr2.includes(x))

difference([2, 1], [3, 2])
// => [1]
Resources: Array#filter Array#includes

differenceBy

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

lodash

// 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 }]

plain js

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

drop

Creates a slice of array with n elements dropped from the beginning.

lodash

// 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]

plain js

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

dropRight

Creates a slice of array with n elements dropped from the end.

lodash

// 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]

plain js

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

fill

Fills elements of array with value from start up to, but not including, end.

lodash

// 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]

plain js

[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

findIndex

This method is like _.find except that it returns the index of the first element predicate returns truthy for instead of the element itself.

lodash

// 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

plain js

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

findLastIndex

This method is like _.findIndex except that it iterates over elements of collection from right to left.

lodash

// 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

plain js

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

flatMap

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.

lodash

// https://lodash.com/docs/#flatMap
import { flatMap } from 'lodash'

flatMap([1, 2], n => [n, n])
// => [1, 1, 2, 2]

plain js

[1, 2].flatMap(n => [n, n])
// => [1, 1, 2, 2]
Resources: Array#flatMap

flatten

Flattens array a single level deep.

lodash

// https://lodash.com/docs/#flatten
import { flatten } from 'lodash'

flatten([1, [2, [3, [4]], 5]])
// => [1, 2, [3, [4]], 5]

plain js

[1, [2, [3, [4]], 5]].flat()
// => [1, 2, [3, [4]], 5]
Resources: Array#flat Source

flattenDeep

Recursively flattens array.

lodash

// https://lodash.com/docs/#flattenDeep
import { flattenDeep } from 'lodash'

flattenDeep([1, [2, [3, [4]], 5]])
// => [1, 2, 3, 4, 5]

plain js

[1, [[2], [3, [4]], 5]].flat(Infinity)
// => [1, 2, 3, 4, 5]
Resources: Array#flat Source

flattenDepth

Recursively flatten array up to depth times.

lodash

// 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]

plain js

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

fromPairs

The inverse of _.toPairs; this method returns an object composed from key-value pairs.

lodash

// https://lodash.com/docs/#fromPairs
import { fromPairs } from 'lodash'

fromPairs([
  ['a', 1],
  ['b', 2],
])
// => { 'a': 1, 'b': 2 }

plain js

Object.fromEntries([
  ['a', 1],
  ['b', 2],
])
// => { 'a': 1, 'b': 2 }
Resources: Object.fromEntries

head

Gets the first element of array.

lodash

// https://lodash.com/docs/#head
import { head } from 'lodash'

head([1, 2, 3])
// => 1

plain js

const [head] = [1, 2, 3]
head
// => 1
Resources: Spread syntax Source

indexOf

Gets the index at which the first occurrence of value is found in array.

lodash

// https://lodash.com/docs/#indexOf
import { indexOf } from 'lodash'

indexOf([1, 2, 3], 3)
// => 2

plain js

[1, 2, 3].indexOf(3)
// => 2
Resources: Array#indexOf

initial

Gets all but the last element of array.

lodash

// https://lodash.com/docs/#initial
import { initial } from 'lodash'

initial([1, 2, 3])
// => [1, 2]

plain js

[1, 2, 3].slice(0, -1)
// => [1, 2]
Resources: Array#slice

intersection

Creates an array of unique values that are included in all given arrays.

lodash

// https://lodash.com/docs/#intersection
import { intersection } from 'lodash'

intersection([2, 1], [2, 3])
// => [2]

plain js

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

intersectionBy

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

lodash

// 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 }]

plain js

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

join

Converts all elements in array into a string separated by separator.

lodash

// https://lodash.com/docs/#join
import { join } from 'lodash'

join(['a', 'b', 'c'], '~')
// => 'a~b~c'

plain js

['a', 'b', 'c'].join('~')
// => 'a~b~c'
Resources: Array#join

last

Gets the last element of array.

lodash

// https://lodash.com/docs/#last
import { last } from 'lodash'

last(['a', 'b', 'c'])
// => 'c'

plain js

const arr = ['a', 'b', 'c']

arr[arr.length - 1]
// => 'c'

lastIndexOf

This method is like _.indexOf except that it iterates over elements of array from right to left.

lodash

// 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

plain js

[1, 2, 1, 2].lastIndexOf(2)
// => 3

// Search from the `fromIndex`
[1, 2, 1, 2].lastIndexOf(2, 2)
// => 1
Resources: Array#lastIndexOf

nth

Gets the element at index n of array. If n is negative, the nth element from the end is returned.

lodash

// https://lodash.com/docs/#nth
import { nth } from 'lodash'

const array = ['a', 'b', 'c', 'd']

nth(array, 1)
// => 'b'

nth(array, -2)
// => 'c';

plain js

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

pull

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.

lodash

// https://lodash.com/docs/#pull
import { pull } from 'lodash'

var array = ['a', 'b', 'c', 'a', 'b', 'c']
pull(array, 'a', 'c')

array
// => ['b', 'b']

plain js

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

pullAt

Removes elements from array corresponding to indexes and returns an array of removed elements.

lodash

// https://lodash.com/docs/#pullAt
import { pullAt } from 'lodash'

const array = ['a', 'b', 'c', 'd']

pullAt(array, [1, 3])
// => ['b', 'd']

array
// => ['a', 'c']

plain js

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

reject

The opposite of _.filter; this method returns the elements of collection that predicate does not return truthy for.

lodash

// 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']]

plain js

['a', 'b', 'c', 'd', 'e', 'f', 'g'].filter(
  char => char !== 'd'
)
// => [['a', 'b', 'c', 'e', 'f', 'g']]
Resources: Array#filter

remove

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

lodash

// 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
// => []

plain js

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

reverse

Reverses array so that the first element becomes the last, the second element becomes the second to last, and so on.

lodash

// https://lodash.com/docs/#reverse
import { reverse } from 'lodash'

const array = [1, 2, 3]

reverse(array)
// => [3, 2, 1]

array
// => [3, 2, 1]

plain js

const array = [1, 2, 3]

array.reverse()
// => [3, 2, 1]

array
// => [3, 2, 1]
Resources: Array#reverse

slice

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.

lodash

// 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 ]

plain js

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

sortedIndexOf

This method is like _.indexOf except that it performs the search on a sorted array.

lodash

// https://lodash.com/docs/#sortedIndexOf
import { sortedIndexOf } from 'lodash'

sortedIndexOf([4, 5, 5, 5, 6], 5)
// => 1

plain js

const sortedIndexOf = (arr, value) => [...arr].sort().indexOf(value)

sortedIndexOf([4, 5, 5, 5, 6], 5)
// => 1
Resources: Array#sort Array#indexOf

sortedLastIndexOf

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.

lodash

// https://lodash.com/docs/#sortedLastIndexOf
import { sortedLastIndexOf } from 'lodash'

sortedLastIndexOf([4, 5, 5, 5, 6], 5)
// => 3

plain js

// 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

sortedUniq

This method is like _.uniq except that it’s designed and optimized for sorted arrays.

lodash

// https://lodash.com/docs/#sortedUniq
import { sortedUniq } from 'lodash'

sortedUniq([1, 1, 2])
// => [1, 2]

plain js

const sortedUniq = arr => [...new Set(arr)].sort()

sortedUniq([1, 1, 2])
// => [1, 2]
Resources: Set Array#sort

tail

Gets all but the first element of array.

lodash

// https://lodash.com/docs/#tail
import { tail } from 'lodash'

tail([1, 2, 3])
// => [2, 3]

plain js

const [, ...tail] = [1, 2, 3]
tail
// => [2, 3]
Resources: Spread syntax Source

take

Creates a slice of array with n elements taken from the beginning.

lodash

// 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)
// => []

plain js

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

takeRight

Creates a slice of array with n elements taken from the end.

lodash

// 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)
// => []

plain js

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

toPairs

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.

lodash

// 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)

plain js

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

union

Creates an array of unique values, in order, from all given arrays.

lodash

// https://lodash.com/docs/#union
import { union } from 'lodash'

union([2], [1, 2], [1, 2])
// => [2, 1]

plain js

const union = (arr, ...args) => [...new Set(arr.concat(...args))]

union([2], [1, 2], [1, 2])
// => [2, 1]
Resources: Spread syntax Set

unionBy

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

lodash

// 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]

plain js

// 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

uniq

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.

lodash

// https://lodash.com/docs/#uniq
import { uniq } from 'lodash'

uniq([2, 1, 2])
// => [2, 1]

plain js

[...new Set([2, 1, 2])]
// => [2, 1]
Resources: Set Source

uniqBy

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

lodash

// 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 }]

plain js

// 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

unzip

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.

lodash

// https://lodash.com/docs/#unzip
import { unzip } from 'lodash'

unzip([
  ['a', 1, true],
  ['b', 2, false],
])
// => [['a', 'b'], [1, 2], [true, false]]

plain js

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

without

Creates an array excluding all given values.

lodash

// 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]

plain js

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

xor

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.

lodash

// 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]

plain js

// 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

zip

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.

lodash

// https://lodash.com/docs/#zip
import { zip } from 'lodash'

zip(['a', 'b'], [1, 2], [true, false])
// => [['a', 1, true], ['b', 2, false]]

plain js

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

zipObject

This method is like _.fromPairs except that it accepts two arrays, one of property identifiers and one of corresponding values.

lodash

// https://lodash.com/docs/#zipObject
import { zipObject } from 'lodash'

zipObject(['a', 'b'], [1, 2])
// => { 'a': 1, 'b': 2 }

plain js

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

collection

every

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

lodash

// https://lodash.com/docs/#every
import { every } from 'lodash'

function isLargerThanTen(element) {
  return element >= 10
}

every([10, 20, 30], isLargerThanTen)
// => true

plain js

function isLargerThanTen(element) {
  return element >= 10
}

[10, 20, 30].every(isLargerThanTen)
// => true
Resources: Array#every Source

filter

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

lodash

// 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]

plain js

function isBigEnough(value) {
  return value >= 10
}

[12, 5, 8, 130, 44].filter(isBigEnough)
// => [12, 130, 44]
Resources: Array#filter Source

find

Iterates over elements of collection, returning the first element predicate returns truthy for. The predicate is invoked with three arguments: (value, index|key, collection).

lodash

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

plain js

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

forEach

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.

lodash

// 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

plain js

;['a', 'b', 'c'].forEach((item, index) => {
  console.log(item, index)
})
// => a 0
// => b 1
// => c 2
Resources: Array#forEach Source

forEachRight

This method is like _.forEach except that it iterates over elements of collection from right to left.

lodash

// 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

plain js

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

includes

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.

lodash

// https://lodash.com/docs/#includes
import { includes } from 'lodash'

includes([1, 2, 3], 1)
// => true

plain js

[1, 2, 3].includes(1)
// => true
Resources: Array#includes Source

map

Creates an array of values by running each element in collection thru iteratee. The iteratee is invoked with three arguments:
(value, index|key, collection).

lodash

// https://lodash.com/docs/#map
import { map } from 'lodash'

map([1, 2, 3], n => n * 3)
// => [3, 6, 9]

plain js

[1, 2, 3].map(n => n * 3)
// => [3, 6, 9]
Resources: Array#map Source

reduce

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

lodash

// 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)

plain js

[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

reduceRight

This method is like _.reduce except that it iterates over elements of collection from right to left.

lodash

// 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]

plain js

[
  [0, 1],
  [2, 3],
  [4, 5],
].reduceRight((flattened, other) => flattened.concat(other), [])
// => [4, 5, 2, 3, 0, 1]
Resources: Array#reduceRight Source

size

Gets the size of collection by returning its length for array-like values or the number of own enumerable string keyed properties for objects.

lodash

// https://lodash.com/docs/#size
import { size } from 'lodash'

size([1, 2, 3])
// => 3

size({ a: 1, b: 2 })
// => 2

size('pebbles')
// => 7

plain js

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

some

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

lodash

// https://lodash.com/docs/#some
import { some } from 'lodash'

const isEven = n => n % 2 === 0

some([3, 4, 5], isEven)
// => true

plain js

const isEven = n => n % 2 === 0

[3, 4, 5].some(isEven)
// => true
Resources: Array#some

date

now

Gets the timestamp of the number of milliseconds that have elapsed since the Unix epoch (1 January 1970 00:00:00 UTC).

lodash

// https://lodash.com/docs/#now
import { now } from 'lodash'

now()
// => # milliseconds  elapsed since the Unix epoch

plain js

Date.now()
// => # milliseconds  elapsed since the Unix epoch
Resources: Date.now

function

after

The opposite of _.before; this method creates a function that invokes func once it’s called n or more times.

lodash

// https://lodash.com/docs/#after
import { after } from 'lodash'

(times, fn) => after(times, fn)

plain js

const after = (times, fn) => {
  let counter = 0

  return (...args) => {
    counter++

    if (counter >= times) {
      return fn(...args)
    }
  }
}

(times, fn) => after(times, fn)
Resources: Spread syntax

ary

Creates a function that invokes func, with up to n arguments, ignoring any additional arguments.

lodash

// https://lodash.com/docs/#ary
import { ary } from 'lodash'

['6', '8', '10'].map(ary(Number.parseInt, 1))
// => [6, 8, 10]

plain js

const ary =
  (fn, arity) =>
  (...args) =>
    fn(...args.slice(0, arity))

['6', '8', '10'].map(ary(Number.parseInt, 1))
// => [6, 8, 10]
Resources: Spread syntax

before

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.

lodash

// https://lodash.com/docs/#before
import { before } from 'lodash'

(times, fn) => before(times, fn)

plain js

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

bind

Creates a function that invokes func with the this binding of thisArg and partials prepended to the arguments it receives.

lodash

// 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!'

plain js

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

bindKey

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.

lodash

// 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!'

plain js

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

curry

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.

lodash

// 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]

plain js

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

curryRight

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.

lodash

// 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]

plain js

// 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

debounce

Creates a debounced function that delays invoking func until after wait milliseconds have elapsed since the last time the debounced function was invoked.

lodash

// https://lodash.com/docs/#debounce
import { debounce } from 'lodash'

(...args) => debounce(...args)

plain js

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

delay

Invokes func after wait milliseconds. Any additional arguments are provided to func when it’s invoked.

lodash

// https://lodash.com/docs/#delay
import { delay } from 'lodash'

fn => delay(fn, 1000, 'later')

plain js

const delay = (fn, timer, ...args) => setTimeout(() => fn(...args), timer)

fn => delay(fn, 1000, 'later')
Resources: Spread syntax

flip

Creates a function that invokes func with arguments reversed.

lodash

// https://lodash.com/docs/#flip
import { flip } from 'lodash'

const flipped = flip((...args) => args)

flipped('a', 'b', 'c', 'd')
// => ['d', 'c', 'b', 'a']

plain js

const flip =
  func =>
  (...args) =>
    func(...args.reverse())

const flipped = flip((...args) => args)

flipped('a', 'b', 'c', 'd')
// => ['d', 'c', 'b', 'a']
Resources: Spread syntax

negate

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.

lodash

// 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]

plain js

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

once

Creates a function that is restricted to invoking func once. Repeat calls to the function return the value of the first invocation.

lodash

// https://lodash.com/docs/#once
import { once } from 'lodash'

fn => once(fn)

plain js

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

overArgs

Creates a function that invokes func with its arguments transformed.

lodash

// 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]

plain js

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

partial

Creates a function that invokes func with partials prepended to the arguments it receives.

lodash

// https://lodash.com/docs/#partial
import { partial } from 'lodash'

const greet = (greeting, name) => `${greeting} ${name}`

const sayHelloTo = partial(greet, 'hello')
sayHelloTo('fred')
// => 'hello fred'

plain js

const partial =
  (func, ...args) =>
  (...furtherArgs) =>
    func(...args, ...furtherArgs)

const greet = (greeting, name) => `${greeting} ${name}`

const sayHelloTo = partial(greet, 'hello')
sayHelloTo('fred')
// => 'hello fred'

partialRight

This method is like _.partial except that partially applied arguments are appended to the arguments it receives.

lodash

// https://lodash.com/docs/#partialRight
import { partialRight } from 'lodash'

const greet = (greeting, name) => `${greeting} ${name}`

const greetFred = partialRight(greet, 'fred')
greetFred('hi')
// => 'hi fred'

plain js

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

rearg

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.

lodash

// 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']

plain js

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

rest

Creates a function that invokes func with the this binding of the created function and arguments from start and beyond provided as an array.

Note: This method is based on the rest parameter.

lodash

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

plain js

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'

spread

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.

lodash

// 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

plain js

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

unary

Creates a function that accepts up to one argument, ignoring any additional arguments.

lodash

// https://lodash.com/docs/#unary
import { unary } from 'lodash'

['6', '8', '10'].map(unary(Number.parseInt))
// => [6, 8, 10]

plain js

const unary = fn => arg => fn(arg)

['6', '8', '10'].map(unary(Number.parseInt))
// => [6, 8, 10]

wrap

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.

lodash

// https://lodash.com/docs/#wrap
import { wrap } from 'lodash'

const sum2 = wrap(2, (a, b, c) => {
  return a + b + c
})

sum2(1, 2)
// => 5

plain js

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

lang

castArray

Casts value as an array if it’s not one.

lodash

// 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

plain js

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

cloneDeep

This method is like _.clone except that it recursively clones value.

fixJSDOMEnvironment

/* istanbul ignore file */
import JSDOMEnvironment from 'jest-environment-jsdom'

// https://github.com/facebook/jest/blob/v29.4.3/website/versioned_docs/version-29.4/Configuration.md#testenvironment-string
export default class FixJSDOMEnvironment extends JSDOMEnvironment {
  constructor(...args) {
    super(...args)

    // FIXME https://github.com/jsdom/jsdom/issues/3363
    this.global.structuredClone = structuredClone
  }
}

lodash

// https://lodash.com/docs/#cloneDeep
import { cloneDeep } from 'lodash'

var objects = [{ 'a': 1 }, { 'b': 2 }]

var deep = cloneDeep(objects)

deep[0] === objects[0]
// => false

plain js

const cloneDeep = object => structuredClone(object)

var objects = [{ 'a': 1 }, { 'b': 2 }]

var deep = cloneDeep(objects)

deep[0] === objects[0]
// => false
Resources: structuredClone

conformsTo

Checks if object conforms to source by invoking the predicate properties of source with the corresponding property values of object.

lodash

// 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

plain js

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

gt

Checks if value is greater than other.

lodash

// https://lodash.com/docs/#gt
import { gt } from 'lodash'

gt(3, 1)
// => true

gt(3, 3)
// => false

gt(1, 3)
// => false

plain js

const gt = (a, b) => a > b

gt(3, 1)
// => true

gt(3, 3)
// => false

gt(1, 3)
// => false
Resources: Comparison Operators

gte

Checks if value is greater than or equal to other.

lodash

// https://lodash.com/docs/#gte
import { gte } from 'lodash'

gte(3, 1)
// => true

gte(3, 3)
// => true

gte(1, 3)
// => false

plain js

const gte = (a, b) => a >= b

gte(3, 1)
// => true

gte(3, 3)
// => true

gte(1, 3)
// => false
Resources: Comparison Operators

isArray

Checks if value is classified as an Array object.

lodash

// https://lodash.com/docs/#isArray
import { isArray } from 'lodash'

isArray([1, 2, 3])
// => true

isArray(document.body.children)
// => false

isArray('abc')
// => false

plain js

Array.isArray([1, 2, 3])
// => true

Array.isArray(document.body.children)
// => false

Array.isArray('abc')
// => false
Resources: Array.isArray

isArrayBuffer

Checks if value is an instance of ArrayBuffer.

lodash

// https://lodash.com/docs/#isArrayBuffer
import { isArrayBuffer } from 'lodash'

isArrayBuffer(new ArrayBuffer(2))
// => true

isArrayBuffer(new Array(2))
// => false

plain js

// 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

isArrayLike

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.

lodash

// 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

plain js

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

isBoolean

Checks if value is classified as a boolean primitive or object.

lodash

// https://lodash.com/docs/#isBoolean
import { isBoolean } from 'lodash'

isBoolean(false)
// => true

isBoolean(null)
// => false

plain js

const isBoolean = arg => arg === !!arg

isBoolean(false)
// => true

isBoolean(null)
// => false

isDate

Checks if value is classified as a Date object.

lodash

// https://lodash.com/docs/#isDate
import { isDate } from 'lodash'

isDate(new Date())
// => true

isDate('Mon April 23 2012')
// => false

plain js

const isDate = d => d instanceof Date && !isNaN(d)

isDate(new Date())
// => true

isDate('Mon April 23 2012')
// => false
Resources: instanceof

isEmpty

Checks if value is an empty object, collection, map, or set.

Objects are considered empty if they have no own enumerable string keyed properties.

Array-like values such as arguments objects, arrays, buffers, strings, or jQuery-like collections are considered empty if they have a length of 0. Similarly, maps and sets are considered empty if they have a size of 0.

lodash

// https://lodash.com/docs/#isEmpty
import { isEmpty } from 'lodash'

isEmpty(null)
// => true

isEmpty(true)
// => true

isEmpty(1)
// => true

isEmpty('not empty')
// => false

isEmpty(new Set([1, 2, 3]))
// => true

isEmpty(new Map([['a', 1]]))
// => false

isEmpty([1, 2, 3])
// => false

isEmpty({ 'a': 1 })
// => false

isEmpty([])
// => true

isEmpty('')
// => true

isEmpty(new Set())
// => true

isEmpty(new Map())
// => true

plain js

const isEmpty = obj =>
  !Object.entries(obj || {}).length && !obj?.length && !obj?.size

isEmpty(null)
// => true

isEmpty(true)
// => true

isEmpty(1)
// => true

isEmpty('not empty')
// => false

isEmpty(new Set([1, 2, 3]))
// => false

isEmpty(new Map([['a', 1]]))
// => false

isEmpty([1, 2, 3])
// => false

isEmpty({ 'a': 1 })
// => false

isEmpty([])
// => true

isEmpty('')
// => true

isEmpty(new Set())
// => true

isEmpty(new Map())
// => true
Resources: Object.entries Set#size Optional Chaining

isError

Checks if value is an Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, or URIError object.

lodash

// https://lodash.com/docs/#isError
import { isError } from 'lodash'

isError(new Error())
// => true

isError(Error)
// => false

plain js

const isError = err => err instanceof Error

isError(new Error())
// => true

isError(Error)
// => false
Resources: instanceof

isFinite

Checks if value is a finite primitive number.

lodash

// https://lodash.com/docs/#isFinite
import { isFinite } from 'lodash'

isFinite(3)
// => true

isFinite(Number.MIN_VALUE)
// => true

isFinite(Infinity)
// => false

isFinite('3')
// => false

plain js

Number.isFinite(3)
// => true

Number.isFinite(Number.MIN_VALUE)
// => true

Number.isFinite(Infinity)
// => false

Number.isFinite('3')
// => false
Resources: Number.isFinite

isFunction

Checks if value is classified as a Function object.

lodash

// https://lodash.com/docs/#isFunction
import { isFunction } from 'lodash'

isFunction(function () {})
// => true

isFunction(() => {})
// => true

isFunction(class NotAFunction {})
// => true

isFunction(/abc/)
// => false

plain js

const isFunction = val => typeof val === 'function'

isFunction(function () {})
// => true

isFunction(() => {})
// => true

isFunction(class NotAFunction {})
// => false

isFunction(/abc/)
// => false
Resources: typeof

isInteger

Checks if value is an integer.

lodash

// https://lodash.com/docs/#isInteger
import { isInteger } from 'lodash'

isInteger(3)
// => true

isInteger(Number.MIN_VALUE)
// => false

isInteger(Infinity)
// => false

isInteger('3')
// => false

plain js

Number.isInteger(3)
// => true

Number.isInteger(Number.MIN_VALUE)
// => false

Number.isInteger(Infinity)
// => false

Number.isInteger('3')
// => false
Resources: Number.isInteger

isMap

Checks if value is classified as a Map object.

lodash

// https://lodash.com/docs/#isMap
import { isMap } from 'lodash'

isMap(new Map())
// => true

isMap(new WeakMap())
// => false

plain js

// 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

isMatch

Performs a partial deep comparison between object and source to determine if object contains equivalent property values.

lodash

// 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

plain js

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

isNaN

Checks if value is NaN.

lodash

// https://lodash.com/docs/#isNaN
import { isNaN } from 'lodash'

isNaN(NaN)
// => true

isNaN(Number(NaN))
// => true

isNaN(undefined)
// => false

plain js

Number.isNaN(NaN)
// => true

Number.isNaN(Number(NaN))
// => true

Number.isNaN(undefined)
// => false
Resources: Number.isNaN

isNil

Checks if value is null or undefined.

lodash

// https://lodash.com/docs/#isNil
import { isNil } from 'lodash'

isNil(null)
// => true

isNil(undefined)
// => true

isNil(NaN)
// => false

plain js

const isNil = val => val == null

isNil(null)
// => true

isNil(undefined)
// => true

isNil(NaN)
// => false
Resources: Comparison Operators

isNull

Checks if value is null.

lodash

// https://lodash.com/docs/#isNull
import { isNull } from 'lodash'

isNull(null)
// => true

isNull(undefined)
// => false

plain js

const isNull = val => val === null

isNull(null)
// => true

isNull(undefined)
// => false
Resources: Equality comparisons

isNumber

Checks if value is classified as a Number primitive or object.

lodash

// https://lodash.com/docs/#isNumber
import { isNumber } from 'lodash'

isNumber(3)
// => true

isNumber(Number.MIN_VALUE)
// => true

isNumber(Infinity)
// => true

isNumber('3')
// => false

plain js

const isNumber = a => typeof a === 'number'

isNumber(3)
// => true

isNumber(Number.MIN_VALUE)
// => true

isNumber(Infinity)
// => true

isNumber('3')
// => false
Resources: typeof

isObject

Checks if value is the language type of Object. (e.g. arrays, functions, objects, regexes, new Number(0), and new String(’’))

lodash

// https://lodash.com/docs/#isObject
import { isObject } from 'lodash'

isObject({})
// => true

isObject([1, 2, 3])
// => true

isObject(() => {})
// => true

isObject(null)
// => false

plain js

const isObject = a => a instanceof Object

isObject({})
// => true

isObject([1, 2, 3])
// => true

isObject(() => {})
// => true

isObject(null)
// => false
Resources: instanceof

isRegExp

Checks if value is classified as a RegExp object.

lodash

// https://lodash.com/docs/#isRegExp
import { isRegExp } from 'lodash'

isRegExp(/abc/)
// => true

isRegExp('/abc/')
// => false

plain js

const isRegExp = obj => obj instanceof RegExp

isRegExp(/abc/)
// => true

isRegExp('/abc/')
// => false
Resources: instanceof

isSafeInteger

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.

lodash

// https://lodash.com/docs/#isSafeInteger
import { isSafeInteger } from 'lodash'

isSafeInteger(3)
// => true

isSafeInteger(Number.MIN_VALUE)
// => false

isSafeInteger(Infinity)
// => false

isSafeInteger('3')
// => false

plain js

const isSafeInteger = n => Number.isSafeInteger(n)

isSafeInteger(3)
// => true

isSafeInteger(Number.MIN_VALUE)
// => false

isSafeInteger(Infinity)
// => false

isSafeInteger('3')
// => false
Resources: Number.isSafeInteger

isSet

Checks if value is an instance of Set.

lodash

// https://lodash.com/docs/#isSet
import { isSet } from 'lodash'

isSet(new Set())
// => true

isSet(new WeakSet())
// => false

plain js

// 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

isString

Checks if value is classified as a String primitive or object.

lodash

// https://lodash.com/docs/#isString
import { isString } from 'lodash'

isString('abc')
// => true

isString(1)
// => false

plain js

const isString = a => typeof a === 'string'

isString('abc')
// => true

isString(1)
// => false
Resources: typeof

isSymbol

Checks if value is an instance of Symbol.

lodash

// https://lodash.com/docs/#isSymbol
import { isSymbol } from 'lodash'

isSymbol(Symbol.iterator)
// => true

isSymbol('abc')
// => false

plain js

const isSymbol = symbolMaybe => typeof symbolMaybe === 'symbol'

isSymbol(Symbol.iterator)
// => true

isSymbol('abc')
// => false

isTypedArray

Checks if value is classified as a typed array.

lodash

import { isTypedArray } from 'util/types'

isTypedArray(new Uint8Array())
// => true

isTypedArray(new Float64Array())
// => true

isTypedArray(new ArrayBuffer())
// => false

plain js

// 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

isUndefined

Checks if value is undefined.

lodash

// https://lodash.com/docs/#isUndefined
import { isUndefined } from 'lodash'

isUndefined(undefined)
// => true

isUndefined(null)
// => false

plain js

const isUndefined = val => val === undefined

isUndefined(undefined)
// => true

isUndefined(null)
// => false
Resources: Equality comparisons

isWeakMap

Checks if value is an instance of WeakMap.

lodash

// https://lodash.com/docs/#isWeakMap
import { isWeakMap } from 'lodash'

isWeakMap(new WeakMap())
// => true

isWeakMap(new WeakSet())
// => false

plain js

// 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

isWeakSet

Checks if value is an instance of WeakSet.

lodash

// https://lodash.com/docs/#isWeakSet
import { isWeakSet } from 'lodash'

isWeakSet(new WeakSet())
// => true

isWeakSet(new WeakMap())
// => false

plain js

// 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

lt

Checks if value is less than other.

lodash

// https://lodash.com/docs/#lt
import { lt } from 'lodash'

lt(1, 3)
// => true

lt(3, 3)
// => false

lt(3, 1)
// => false

plain js

const lt = (a, b) => a < b

lt(1, 3)
// => true

lt(3, 3)
// => false

lt(3, 1)
// => false
Resources: Comparison Operators

lte

Checks if value is less than or equal to other.

lodash

// https://lodash.com/docs/#lte
import { lte } from 'lodash'

lte(1, 3)
// => true

lte(3, 3)
// => true

lte(3, 1)
// => false

plain js

const lte = (a, b) => a <= b

lte(1, 3)
// => true

lte(3, 3)
// => false

lte(3, 1)
// => false
Resources: Comparison Operators

math

add

Adds two numbers.

lodash

// https://lodash.com/docs/#add
import { add } from 'lodash'

add(6, 4)
// => 10

plain js

const add = (a, b) => a + b

add(6, 4)
// => 10

ceil

Computes number rounded up to precision.

lodash

// https://lodash.com/docs/#ceil
import { ceil } from 'lodash'

ceil(4.006)
// => 5

ceil(6.004, 2)
// => 6.01

ceil(6040, -2)
// => 6100

plain js

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

Divide two numbers.

lodash

// https://lodash.com/docs/#divide
import { divide } from 'lodash'

divide(6, 4)
// => 1.5

plain js

const divide = (a, b) => a / b

divide(6, 4)
// => 1.5

floor

Computes number rounded down to precision.

lodash

// https://lodash.com/docs/#floor
import { floor } from 'lodash'

floor(4.006)
// => 4

floor(0.046, 2)
// => 0.04

floor(4060, -2)
// => 4000

plain js

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

max

Computes the maximum value of array. If array is empty or falsey, undefined is returned.

lodash

// https://lodash.com/docs/#max
import { max } from 'lodash'

max([4, 2, 8, 6])
// => 8

max([])
// => undefined

plain js

const max = nums => {
  if (nums.length) return Math.max(...nums)
}

max([4, 2, 8, 6])
// => 8

max([])
// => undefined
Resources: Spread syntax

maxBy

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

lodash

// https://lodash.com/docs/#maxBy
import { maxBy } from 'lodash'

const objects = [{ n: 1 }, { n: 2 }]

maxBy(objects, o => o.n)
// => { 'n': 2 }

plain js

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

mean

Computes the mean of the values in array.

lodash

// https://lodash.com/docs/#mean
import { mean } from 'lodash'

mean([4, 2, 8, 6])
// => 5

plain js

const mean = arr => arr.reduce((acc, num) => acc + num, 0) / arr.length

mean([4, 2, 8, 6])
// => 5
Resources: Array#reduce

meanBy

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

lodash

// 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

plain js

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

min

Computes the minimum value of array. If array is empty or falsey, undefined is returned.

lodash

// https://lodash.com/docs/#min
import { min } from 'lodash'

min([4, 2, 8, 6])
// => 2

min([])
// => undefined

plain js

const min = nums => {
  if (nums.length) return Math.min(...nums)
}

min([4, 2, 8, 6])
// => 2

min([])
// => undefined
Resources: Spread syntax

minBy

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

lodash

// https://lodash.com/docs/#minBy
import { minBy } from 'lodash'

const objects = [{ n: 1 }, { n: 2 }]

minBy(objects, o => o.n)
// => { 'n': 1 }

plain js

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

Multiply two numbers.

lodash

// https://lodash.com/docs/#multiply
import { multiply } from 'lodash'

multiply(6, 4)
// => 24

plain js

const multiply = (a, b) => a * b

multiply(6, 4)
// => 24

round

Computes number rounded to precision.

lodash

// https://lodash.com/docs/#round
import { round } from 'lodash'

round(4.006)
// => 4

round(4.006, 2)
// => 4.01

round(4060, -2)
// => 4100

plain js

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

Subtract two numbers.

lodash

// https://lodash.com/docs/#subtract
import { subtract } from 'lodash'

subtract(6, 4)
// => 2

plain js

const subtract = (a, b) => a - b

subtract(6, 4)
// => 2

sum

Computes the sum of the values in array.

lodash

// https://lodash.com/docs/#sum
import { sum } from 'lodash'

sum([4, 2, 8, 6])
// => 20

plain js

[4, 2, 8, 6].reduce((acc, num) => {
  acc += num
  return acc
}, 0)
// => 20
Resources: Array#reduce

sumBy

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

lodash

// 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

plain js

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

number

clamp

Clamps number within the inclusive lower and upper bounds.

lodash

// https://lodash.com/docs/#clamp
import { clamp } from 'lodash'

clamp(-10, -5)
// => -10

clamp(-10, -5, 5)
// => -5

clamp(10, -5, 5)
// => 5

plain js

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

inRange

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.

lodash

// 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

plain js

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

random

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.

lodash

// 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

plain js

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

object

assign

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.

lodash

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

plain js

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

create

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.

lodash

// 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

plain js

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

defaults

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.

lodash

// https://lodash.com/docs/#defaults
import { defaults } from 'lodash'

defaults({ a: 1 }, { b: 2 }, { a: 3 })
// // => { 'a': 1, 'b': 2 }

plain js

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

get

Gets the value at path of object. If the resolved value is undefined, the defaultValue is returned in its place.

lodash

// 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

plain js

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

has

Checks if path is a direct property of object.

lodash

// 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

plain js

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

invert

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.

lodash

// https://lodash.com/docs/#invert
import { invert } from 'lodash'

const object = { a: 1, b: 2, c: 1 }

invert(object)
// => { '1': 'c', '2': 'b' }

plain js

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

keys

Creates an array of the own enumerable property names of object.

lodash

// 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']

plain js

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

mapKeys

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

lodash

// https://lodash.com/docs/#mapKeys
import { mapKeys } from 'lodash'

mapKeys({ a: 1, b: 2 }, (value, key) => key + value)
// => { 'a1': 1, 'b2': 2 }

plain js

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

omit

The opposite of _.pick; this method creates an object composed of the own and inherited enumerable property paths of object that are not omitted.

lodash

// https://lodash.com/docs/#omit
import { omit } from 'lodash'

const object = { a: 1, b: '2', c: 3 }

omit(object, ['a', 'c'])
// => { 'b': '2' }

plain js

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

omitBy

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

lodash

// https://lodash.com/docs/#omitBy
import { omitBy, isNumber } from 'lodash'

const object = { a: 1, b: '2', c: 3 }

omitBy(object, isNumber)
// => { 'b': '2' }

plain js

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

pick

Creates an object composed of the picked object properties.

lodash

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

plain js

const object = {
  a: 1,
  b: 2,
  c: 3,
}

const { a, c } = object

{ a, c }
// => {a: 1, c: 3}
Resources: Object destructuring

set

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.

lodash

// 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

plain js

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

unset

Removes the property at path of object.

Note: This method mutates object.

lodash

// 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 } }] };

plain js

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

values

Creates an array of the own enumerable string keyed property values of object.

lodash

// 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}]

plain js

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

string

capitalize

Converts the first character of string to upper case and the remaining to lower case.

lodash

// https://lodash.com/docs/#capitalize
import { capitalize } from 'lodash'

capitalize('FRED')
// => 'Fred'

plain js

const capitalize = str =>
  `${str.charAt(0).toUpperCase()}${str.slice(1).toLowerCase()}`

capitalize('FRED')
// => 'Fred'
Resources: String#charAt String#slice

deburr

Deburrs string by converting Latin-1 Supplement and Latin Extended-A letters to basic Latin letters and removing combining diacritical marks.

lodash

// 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']

plain js

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

endsWith

Checks if string ends with the given target string.

lodash

// https://lodash.com/docs/#endsWith
import { endsWith } from 'lodash'

endsWith('pinecone', 'cone')
// => true

plain js

'pinecone'.endsWith('cone')
// => true
Resources: endsWith

escape

Converts the characters “&”, “<”, “>”, ‘"’, and “’” in string to their corresponding HTML entities.

Note: No other characters are escaped.

lodash

// https://lodash.com/docs/#escape
import { escape } from 'lodash'

escape('fred, barney, & pebbles')
// => 'fred, barney, &amp; pebbles'

plain js

const escape = str => {
  const map = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#39;',
  }
  return str.replace(/[&<>"']/g, m => map[m])
}

escape('fred, barney, & pebbles')
// => 'fred, barney, &amp; pebbles'
Resources: String#replace

kebabCase

Converts string to kebab case.

lodash

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

plain js

// 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

lowerFirst

Converts the first character of string to lower case.

lodash

// https://lodash.com/docs/#lowerFirst
import { lowerFirst } from 'lodash'

lowerFirst('Fred')
// => 'fred'

lowerFirst('FRED')
// => 'fRED'

plain js

const lowerFirst = str => `${str.charAt(0).toLowerCase()}${str.slice(1)}`

lowerFirst('Fred')
// => 'fred'

lowerFirst('FRED')
// => 'fRED'
Resources: String#charAt String#slice

pad

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.

lodash

// https://lodash.com/docs/#pad
import { pad } from 'lodash'

pad('abc', 8)
// // => '  abc   '
//
pad('abc', 8, '_-')
// // => '_-abc_-_'
//
pad('abc', 3)
// // => 'abc'

plain js

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

padEnd

Pads string on the right side if it’s shorter than length. Padding characters are truncated if they exceed length.

lodash

// https://lodash.com/docs/#padEnd
import { padEnd } from 'lodash'

padEnd('abc', 6)
// => 'abc   '

padEnd('abc', 6, '_-')
// => 'abc_-_'

padEnd('abc', 3)
// => 'abc'

plain js

'abc'.padEnd(6)
// => 'abc   '

'abc'.padEnd(6, '_-')
// => 'abc_-_'

'abc'.padEnd(3)
// => 'abc'
Resources: String#padEnd

padStart

Pads string on the left side if it’s shorter than length. Padding characters are truncated if they exceed length.

lodash

// https://lodash.com/docs/#padStart
import { padStart } from 'lodash'

padStart('abc', 6)
// => '   abc'

padStart('abc', 6, '_-')
// => '_-_abc'

padStart('abc', 3)
// => 'abc'

plain js

'abc'.padStart(6)
// => '   abc'

'abc'.padStart(6, '_-')
// => '_-_abc'

'abc'.padStart(3)
// => 'abc'
Resources: String#padStart

parseInt

Converts string to an integer of the specified radix.

lodash

// https://lodash.com/docs/#parseInt
import { parseInt } from 'lodash'

parseInt('08')
// => 8

['6', '08', '10'].map(parseInt)
// => [6, 8, 10]

plain js

parseInt('08', 10)
// => 8

['6', '08', '10'].map(i => parseInt(i, 10))
// => [6, 8, 10]
Resources: parseInt

repeat

Repeats the given string n times.

lodash

// https://lodash.com/docs/#repeat
import { repeat } from 'lodash'

repeat('*', 3)
// => '***'

repeat('abc', 2)
// => 'abcabc'

repeat('abc', 0)
// => ''

plain js

'*'.repeat(3)
// => '***'

'abc'.repeat(2)
// => 'abcabc'

'abc'.repeat(0)
// => ''
Resources: String#repeat

replace

Replaces matches for pattern in string with replacement.

lodash

// https://lodash.com/docs/#replace
import { replace } from 'lodash'

replace('Hi Fred', 'Fred', 'Barney')
// => 'Hi Barney'

plain js

const replace = (str, s, r) => str.replace(s, r)

replace('Hi Fred', 'Fred', 'Barney')
// => 'Hi Barney'
Resources: String#replace

split

Splits string by separator.

lodash

// 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', '👨‍👨‍👧‍👦']

plain js

'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

startsWith

Checks if string starts with the given target string.

lodash

// https://lodash.com/docs/#startsWith
import { startsWith } from 'lodash'

startsWith('JavaScript', 'Java')
// => true

plain js

'JavaScript'.startsWith('Java')
// => true
Resources: String#startsWith

toLower

Converts string, as a whole, to lower case.

lodash

// https://lodash.com/docs/#toLower
import { toLower } from 'lodash'

toLower('--Foo-Bar--')
// => '--foo-bar--'

toLower('fooBar')
// => 'foobar'

toLower('__FOO_BAR__')
// => '__foo_bar__'

plain js

const toLower = str => str.toLowerCase()

toLower('--foo-bar--')
// => '--foo-bar--'

toLower('fooBar')
// => 'foobar'

toLower('__foo_bar__')
// => '__foo_bar__'

toUpper

Converts string, as a whole, to upper case just like String#toUpperCase.

lodash

// https://lodash.com/docs/#toUpper
import { toUpper } from 'lodash'

toUpper('--foo-bar--')
// => '--FOO-BAR--'

toUpper('fooBar')
// => 'FOOBAR'

toUpper('__foo_bar__')
// => '__FOO_BAR__'

plain js

const toUpper = str => str.toUpperCase()

toUpper('--foo-bar--')
// => '--FOO-BAR--'

toUpper('fooBar')
// => 'FOOBAR'

toUpper('__foo_bar__')
// => '__FOO_BAR__'

trim

Removes leading and trailing whitespace or specified characters from string.

lodash

// https://lodash.com/docs/#trim
import { trim } from 'lodash'

trim(' abc ')
// => 'abc'

trim('-_-abc-_-', '_-')
// => 'abc'

[' foo ', ' bar '].map(trim)
// => ['foo', 'bar']

plain js

// 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

trimEnd

Removes trailing whitespace or specified characters from string.

lodash

// https://lodash.com/docs/#trimEnd
import { trimEnd } from 'lodash'

trimEnd(' abc ')
// => ' abc'

trimEnd('-_-abc-_-', '_-')
// => '-_-abc'

plain js

// 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

trimStart

Removes leading whitespace or specified characters from string.

lodash

// https://lodash.com/docs/#trimStart
import { trimStart } from 'lodash'

trimStart(' abc ')
// => 'abc '

trimStart('-_-abc-_-', '_-')
// => 'abc-_-'

plain js

// 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

upperFirst

Converts the first character of string to upper case.

lodash

// https://lodash.com/docs/#upperFirst
import { upperFirst } from 'lodash'

upperFirst('fred')
// => 'Fred'

upperFirst('FRED')
// => 'FRED'

plain js

const upperFirst = str => `${str.charAt(0).toUpperCase()}${str.slice(1)}`

upperFirst('fred')
// => 'Fred'

upperFirst('FRED')
// => 'FRED'
Resources: String#charAt String#slice

util

attempt

Attempts to invoke func, returning either the result or the caught error object. Any additional arguments are provided to func when it’s invoked.

lodash

// 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]

plain js

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

cond

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.

lodash

// 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

plain js

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

constant

Creates a function that returns value.

lodash

// https://lodash.com/docs/#constant
import { constant } from 'lodash'

const return42 = constant(42)
return42()
// => 42

plain js

const constant = arg => () => arg
const return42 = constant(42)

return42()
// => 42

defaultTo

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.

lodash

// 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

plain js

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

flow

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.

lodash

// 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

plain js

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

flowRight

This method is like _.flow except that it creates a function that invokes the given functions from right to left.

lodash

// 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

plain js

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

identity

This method returns the first argument it receives.

lodash

// https://lodash.com/docs/#identity
import { identity } from 'lodash'

const object = { a: 1 }

identity(object) === object
// => true

plain js

const identity = a => a

const object = { a: 1 }

identity(object) === object
// => true

noop

This method returns undefined.

lodash

// https://lodash.com/docs/#noop
import { noop } from 'lodash'

noop()
// => undefined

plain js

const noop = () => {}

noop()
// => undefined

nthArg

Creates a function that gets the argument at index n. If n is negative, the nth argument from the end is returned.

lodash

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

plain js

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

over

Creates a function that invokes iteratees with the arguments it receives and returns their results.

lodash

// https://lodash.com/docs/#over
import { over } from 'lodash'

const func = over([Math.max, Math.min])

func(1, 2, 3, 4)
// => [4, 1]

plain js

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

overEvery

Creates a function that checks if all of the predicates return truthy when invoked with the arguments it receives.

lodash

// https://lodash.com/docs/#overEvery
import { overEvery } from 'lodash'

const func = overEvery([Boolean, isFinite])

func('1')
// => true

func(null)
// => false

func(NaN)
// => false

plain js

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

overSome

Creates a function that checks if any of the predicates return truthy when invoked with the arguments it receives.

lodash

// https://lodash.com/docs/#overSome
import { overSome } from 'lodash'

const func = overSome([Boolean, isFinite])

func('1')
// => true

func(null)
// => true

func(NaN)
// => false

plain js

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

range

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.

lodash

// 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)
// => []

plain js

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

rangeRight

This method is like _.range except that it populates values in descending order.

lodash

// 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)
// => []

plain js

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

stubArray

This method returns a new empty array.

lodash

// https://lodash.com/docs/#stubArray
import { stubArray } from 'lodash'

stubArray()
// => []

plain js

const stubArray = () => []

stubArray()
// => []

stubFalse

This method returns false.

lodash

// https://lodash.com/docs/#stubFalse
import { stubFalse } from 'lodash'

stubFalse()
// => false

plain js

const stubFalse = () => false

stubFalse()
// => false

stubObject

This method returns a new empty object.

lodash

// https://lodash.com/docs/#stubObject
import { stubObject } from 'lodash'

stubObject()
// => {}

plain js

const stubObject = () => ({})

stubObject()
// => {}

stubString

This method returns an empty string.

lodash

// https://lodash.com/docs/#stubString
import { stubString } from 'lodash'

stubString()
// => ''

plain js

const stubString = () => ''

stubString()
// => ''

stubTrue

This method returns true.

lodash

// https://lodash.com/docs/#stubTrue
import { stubTrue } from 'lodash'

stubTrue()
// => true

plain js

const stubTrue = () => true

stubTrue()
// => true

times

Invokes the iteratee n times, returning an array of the results of each invocation. The iteratee is invoked with one argument; (index).

lodash

// https://lodash.com/docs/#times
import { times } from 'lodash'

times(3)
// => [0, 1, 2]

times(3, i => i + 3)
// => [3, 4, 5]

plain js

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

toPath

Converts value to a property path array.

lodash

// 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']

plain js

// 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']

uniqueId

Generates a unique ID. If prefix is given, the ID is appended to it.

lodash

// https://lodash.com/docs/#uniqueId
import { uniqueId } from 'lodash'

uniqueId('contact_')
// => 'contact_1'

uniqueId()
// => '2'

plain js

const uniqueId = (
  counter =>
  (str = '') =>
    `${str}${++counter}`
)(0)

uniqueId('contact_')
// => 'contact_1'

uniqueId()
// => '2'
Resources: IIFE

🔝