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

each

lodash

import { each } from 'lodash'

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

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

each(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

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 }

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