YOU MIGHT NOT NEED LODASH

Lodash is a great library, well crafted, battle tested and with a strong team.
Just to be clear: You should use Lodash - just make sure you import the bits you need, not the whole library to use one method.

This page is a mere exercise to see how can achieve the same functionalities in plain js: sometimes it's nice to understand the nitty gritty details of what we are building or how stuff works behind the hood.

The project is far from complete: this is the list of Lodash methods left.
Please contribute on github.

array

chunk

lodash

import { chunk } from 'lodash'

chunk(['a', 'b', 'c', 'd', 'e', 'f', 'g'], 3)
// => [['a', 'b', 'c'], ['d', 'e', 'f'], ['g']]

plain js

const chunk = (arr, chunkSize, cache = []) => {
  const tmp = [...arr]
  while (tmp.length) cache.push(tmp.splice(0, chunkSize))
  return cache
}

chunk(['a', 'b', 'c', 'd', 'e', 'f', 'g'], 3)
// => [['a', 'b', 'c'], ['d', 'e', 'f'], ['g']]

compact

lodash

import { compact } from 'lodash'

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

plain js

[0, 1, 2].filter(x => !!x)
// => [1, 2]

concat

lodash

import { concat } from 'lodash'

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

plain js

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

difference

lodash

import { difference } from 'lodash'

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

plain js

[2, 1].filter(x => ![3, 2].includes(x))
// => [1]

differenceBy

lodash

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

[2.1, 1.2].filter(a => ![2.3, 3.4].map(Math.floor).includes(Math.floor(a)))
// => [1.2]

// The `_.property` iteratee shorthand.
[{ x: 2 }, { x: 1 }].filter(a => ![{ x: 1 }].map(b => b.x).includes(a.x))
// => [{ 'x': 2 }]

drop

lodash

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]

dropRight

lodash

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) => n && arr.slice(0, -n) || arr

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]

fill

lodash

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]

findIndex

lodash

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

flatten

lodash

import { flatten } from 'lodash'

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

plain js

[1, [2, [3, [4]], 5]].reduce((a, b) => a.concat(b), [])
// => [1, 2, [3, [4]], 5]

flattenDeep

lodash

import { flattenDeep } from 'lodash'

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

plain js

const flattenDeep = arr => Array.isArray(arr)
  ? arr.reduce((a, b) => [...flattenDeep(a), ...flattenDeep(b)], [])
  : [arr]

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

fromPairs

lodash

import { fromPairs } from 'lodash'

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

plain js

const fromPairs = pairs => pairs.reduce((cache, pair) => {
  cache[pair[0]] = pair[1]
  return cache
}, {})


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

head

lodash

import { head } from 'lodash'

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

plain js

const [head, ...tail] = [1, 2, 3] // eslint-disable-line
head
// => 1

indexOf

lodash

import { indexOf } from 'lodash'

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

plain js

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

initial

lodash

import { initial } from 'lodash'

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

plain js

[1, 2, 3].slice(0, -1)
// => [1, 2]

join

lodash

import { join } from 'lodash'

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

plain js

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

last

lodash

import { last } from 'lodash'

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

plain js

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

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

lastIndexOf

lodash

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

reject

lodash

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

tail

lodash

import { tail } from 'lodash'

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

plain js

const [head, ...tail] = [1, 2, 3] //eslint-disable-line
tail
// => [2, 3]

uniq

lodash

import { uniq } from 'lodash'

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

plain js

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

collection

every

lodash

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

filter

lodash

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]

find

lodash

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 }

forEach

lodash

import { forEach } from 'lodash'

function iteratee (item, index) {
  console.log(item, index)
}

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

forEach(array, iteratee)
// => a 0
// => b 1
// => c 2

plain js

function iteratee (item, index) {
  console.log(item, index)
}

['a', 'b', 'c'].forEach(iteratee)
// => a 0
// => b 1
// => c 2

includes

lodash

import { includes } from 'lodash'

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

plain js

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

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

map

lodash

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]

reduce

lodash

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)

reduceRight

lodash

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]

size

lodash

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

date

now

lodash

import { now } from 'lodash'

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

plain js

(new Date()).getTime()
// => # milliseconds  elapsed since the Unix epoch

math

add

lodash

import { add } from 'lodash'

add(6, 4)
// => 10

plain js

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

add(6, 4)
// => 10

ceil

lodash

import { ceil } from 'lodash'

ceil(4.006)
// => 5

ceil(6.004, 2)
// => 6.01

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

plain js

const ceil = (num, precision = 0) => {
  const modifier = 10 ** precision
  return !modifier ? Math.ceil(num) : Math.ceil(num * modifier) / modifier
}

ceil(4.006)
// => 5

ceil(6.004, 2)
// => 6.01

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

divide

lodash

import { divide } from 'lodash'

divide(6, 4)
// => 1.5

plain js

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

divide(6, 4)
// => 1.5

floor

lodash

import { floor } from 'lodash'

floor(4.006)
// => 4

floor(0.046, 2)
// => 0.04

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

plain js

const floor = (num, precision = 0) => {
  const modifier = 10 ** precision
  return !modifier ? Math.floor(num) : Math.floor(num * modifier) / modifier
}

floor(4.006)
// => 4

floor(0.046, 2)
// => 0.04

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

max

lodash

import { max } from 'lodash'

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

max([])
// => undefined

plain js

const max = nums => (nums.length ? Math.max(...nums) : undefined)

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

max([])
// => undefined

maxBy

lodash

import { maxBy } from 'lodash'

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

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

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

plain js

const maxBy = (arr, iteratee) => {
  const func = typeof iteratee === 'function' ? iteratee : item => item[iteratee]
  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 }

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

mean

lodash

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

meanBy

lodash

import { meanBy } from 'lodash'

const objects = [{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }]

meanBy(objects, o => o.n)
// => 5

meanBy(objects, 'n')
// => 5

plain js

const minBy = (arr, iteratee) => {
  const func = typeof iteratee === 'function' ? iteratee : item => item[iteratee]
  return arr.reduce((acc, item) => acc + func(item), 0) / arr.length
}

const objects = [{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }]

minBy(objects, o => o.n)
// => 5

minBy(objects, 'n')
// => 5

min

lodash

import { min } from 'lodash'

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

min([])
// => undefined

plain js

const min = nums => (nums.length ? Math.min(...nums) : undefined)

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

min([])
// => undefined

minBy

lodash

import { minBy } from 'lodash'

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

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

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

plain js

const minBy = (arr, iteratee) => {
  const func = typeof iteratee === 'function' ? iteratee : item => item[iteratee]
  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 }

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

multiply

lodash

import { multiply } from 'lodash'

multiply(6, 4)
// => 24

plain js

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

multiply(6, 4)
// => 24

round

lodash

import { round } from 'lodash'

round(4.006)
// => 4

round(4.006, 2)
// => 4.01

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

plain js

const round = (num, precision = 0) => {
  const modifier = 10 ** precision
  return !modifier ? Math.round(num) : Math.round(num * modifier) / modifier
}

round(4.006)
// => 4

round(4.006, 2)
// => 4.01

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

subtract

lodash

import { subtract } from 'lodash'

subtract(6, 4)
// => 2

plain js

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

subtract(6, 4)
// => 2

sum

lodash

import { sum } from 'lodash'

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

plain js

const sum = arr =>
  arr.reduce((acc, num) => {
    acc += num
    return acc
  }, 0)

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

sumBy

lodash

import { sumBy } from 'lodash'

const objects = [{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }]

sumBy(objects, o => o.n)
// => 20

sumBy(objects, 'n')
// => 20

plain js

const sumBy = (arr, iteratee) => {
  const func = typeof iteratee === 'function' ? iteratee : item => item[iteratee]

  return arr.reduce((acc, item) => acc + func(item), 0)
}

const objects = [{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }]

sumBy(objects, o => o.n)
// => 20

// The `_.property` iteratee shorthand.
sumBy(objects, 'n')
// => 20

number

clamp

lodash

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

lodash

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

object

values

lodash

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