Lodash: an introdution

Contents

  • Sorry... What?
  • But... Why?
  • Manipulate arrays
  • Manipulate objects
  • Other gems
  • Questions

Sorry... What?

Sorry... What??

Lodash is...

Aside from awesome -> Marketing stuff:

 

  • "A modern JavaScript utility library delivering modularity, performance & extras." (lodash.com)
  • "Lodash is a JS helper library for arrays, strings and objects."
  • "Lodash is the equivalent of the Batman’s utility belt for Javascript"

 

Sorry... What??

Lodash is...

Sorry... What??

The "Why Lodash"

It's functional! (buzz word people [used to?] love)

"Save time by not coding generic functions. Cleaner code. Less lines. Compatible with all browsers."

"Lodash makes JavaScript easier by taking the hassle out of working with arrays, numbers, objects, strings, etc."

Sorry... What??

Great documentation with light background, so clearly for frontend people next to windows, but good to bringing light to backend teams.

The "Why Lodash"

But... Why?

But... Why?

  • Some colleagues don't know lodash exists and could use it
  • Lots of functions -> Curate the most useful ones
  • Provide additional explanation / examples (with [hopefully] help from Rubén and Javi)

Manipulate arrays

Manipulate Arrays

Filter items by value

Mutating

Non-Mutating

var array = ['a', 'b', 'c', 'a', 'b', 'c'];
 
_.pull(array, 'a', 'c');
console.log(array);
// => ['b', 'b']
_.without([2, 1, 2, 3], 1, 2);
// => [3]

Manipulate Arrays

Filter items by predicate

Mutating

Non-Mutating

var array = [1, 2, 3, 4];
var evens = _.remove(array, function(n) {
  return n % 2 == 0;
});
 
console.log(array);
// => [1, 3]
 
console.log(evens);
// => [2, 4]
var users = [
  { 'user': 'barney', 'age': 36, 'active': true },
  { 'user': 'fred',   'age': 40, 'active': false }
];
 
_.filter(users, function(o) { return !o.active; });
// => objects for ['fred']

Manipulate Arrays

var users = [
  { 'user': 'barney', 'age': 36, 'active': true },
  { 'user': 'fred',   'age': 40, 'active': false }
];
 
_.filter(users, function(o) { return !o.active; });
// => objects for ['fred']

// The `_.matches` iteratee shorthand.
_.filter(users, { 'age': 36, 'active': true });
// => objects for ['barney']
 
// The `_.matchesProperty` iteratee shorthand.
_.filter(users, ['active', false]);
// => objects for ['fred']
 
// The `_.property` iteratee shorthand.
_.filter(users, 'active');
// => objects for ['barney']

_.filter(collection, [predicate=_.identity])

The different flavours for 'predicate'

Manipulate Arrays

Check items for condition

true for all: _.every()

true for one: _.some()

_.every([true, 1, null, 'yes'], Boolean);
// => false
 
var users = [
  { 'user': 'barney', 'age': 36, 'active': false },
  { 'user': 'fred',   'age': 40, 'active': false }
];
 
// The `_.matches` iteratee shorthand.
_.every(users, { 'user': 'barney', 'active': false });
// => false
_.some([null, 0, 'yes', false], Boolean);
// => true
 
var users = [
  { 'user': 'barney', 'active': true },
  { 'user': 'fred',   'active': false }
];
 
// The `_.matches` iteratee shorthand.
_.some(users, { 'user': 'barney', 'active': false });
// => false

Manipulate Arrays

Sort items

simple: _.sortBy()

need desc? _.orderBy()

var users = [
  { 'user': 'fred',   'age': 48 },
  { 'user': 'barney', 'age': 36 },
  { 'user': 'fred',   'age': 40 },
  { 'user': 'barney', 'age': 34 }
];
 
_.sortBy(users, ['user', 'age']);
// => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]]
var users = [
  { 'user': 'fred',   'age': 48 },
  { 'user': 'barney', 'age': 34 },
  { 'user': 'fred',   'age': 40 },
  { 'user': 'barney', 'age': 36 }
];
 
// Sort by `user` in ascending order and by `age` in descending order.
_.orderBy(users, ['user', 'age'], ['asc', 'desc']);
// => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]

Manipulate Arrays

Find element

first: _.find()

last: _.findLast()

var users = [
  { 'user': 'barney',  'age': 36, 'active': true },
  { 'user': 'fred',    'age': 40, 'active': false },
  { 'user': 'pebbles', 'age': 1,  'active': true }
];
 
_.find(users, function(o) { return o.age < 40; });
// => object for 'barney'
 
_.findLast(users, function(o) { return o.age < 40; });
// => object for 'pebbles'

Find element index

first: _.findIndex()

last: _.findLastIndex()

var users = [
  { 'user': 'barney',  'active': false },
  { 'user': 'fred',    'active': false },
  { 'user': 'pebbles', 'active': true }
];
 
_.findIndex(users, function(o) { return o.user == 'barney'; });
// => 0

_.findLastIndex(users, ['active', false]);
// => 2

Manipulate Arrays

Map and reduce

lodash's _.map() is commonly used to get an array of object properties

var users = [
  { 'user': 'barney' },
  { 'user': 'fred' }
];
 
// The `_.property` iteratee shorthand.
_.map(users, 'user');
// => ['barney', 'fred']
_.map([4, 8], square);
// => [16, 64]

Simple _.map() use

Manipulate Arrays

Map and reduce

_.reduce() as usual

_.reduce([1, 2], function(sum, n) {
  return sum + n;
}, 0);
// => 3
 
_.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
  (result[value] || (result[value] = [])).push(key);
  return result;
}, {});
// => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed)

Manipulate Arrays

Convert a 'list' to a 'dictionary'

_.keyBy(): one object for each key

var array = [
  { 'dir': 'left', 'code': 97 },
  { 'dir': 'right', 'code': 100 }
];
 
_.keyBy(array, function(o) {
  return String.fromCharCode(o.code);
});
// => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
 
_.keyBy(array, 'dir');
// => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }

Manipulate Arrays

Convert a 'list' to a 'dictionary'

_.groupBy(): an array for each key

_.groupBy([6.1, 4.2, 6.3], Math.floor);
// => { '4': [4.2], '6': [6.1, 6.3] }
 
// The `_.property` iteratee shorthand.
_.groupBy(['one', 'two', 'three'], 'length');
// => { '3': ['one', 'two'], '5': ['three'] }

Manipulate objects

Manipulate Objects

Iterate

Only own properties: _.forOwn

function Foo() {
  this.a = 1;
  this.b = 2;
}
 
Foo.prototype.c = 3;
 
_.forOwn(new Foo, function(value, key) {
  console.log(key);
});
// => Logs 'a' then 'b' (iteration order is not guaranteed).

Manipulate Objects

Iterate

Own and inherited properties: _.forIn

function Foo() {
  this.a = 1;
  this.b = 2;
}
 
Foo.prototype.c = 3;
 
_.forIn(new Foo, function(value, key) {
  console.log(key);
});
// => Logs 'a', 'b', then 'c' (iteration order is not guaranteed).

Manipulate Objects

Generate new objects

All properites except some: _.omit()

var object = { 'a': 1, 'b': '2', 'c': 3 };
 
_.omit(object, ['a', 'c']);
// => { 'b': '2' }

Only some properties: _.pick() [much faster]

var object = { 'a': 1, 'b': '2', 'c': 3 };
 
_.pick(object, ['a', 'c']);
// => { 'a': 1, 'c': 3 }

Also _.omitBy() and _.pickBy()

Manipulate Objects

Generate arrays

Array of keys: _.keys()

function Foo() {
  this.a = 1;
  this.b = 2;
}
 
Foo.prototype.c = 3;
 
_.keys(new Foo);
// => ['a', 'b'] (iteration order is not guaranteed)

Manipulate Objects

Generate arrays

Array of values: _.values()

function Foo() {
  this.a = 1;
  this.b = 2;
}
 
Foo.prototype.c = 3;
 
_.values(new Foo);
// => [1, 2] (iteration order is not guaranteed)

Manipulate Objects

Generate arrays

Map values: _.mapValues()

var users = {
  'fred':    { 'user': 'fred',    'age': 40 },
  'pebbles': { 'user': 'pebbles', 'age': 1 }
};
 
_.mapValues(users, function(o) { return o.age; });
// => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
 
// The `_.property` iteratee shorthand.
_.mapValues(users, 'age');
// => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)

Manipulate Objects

Generate arrays

Map Keys: _.mapKeys()

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

Manipulate Objects

Work with properties

_.get()

var object = { 'a': [{ 'b': { 'c': 3 } }] };
 
_.get(object, 'a[0].b.c');
// => 3
 
_.get(object, ['a', '0', 'b', 'c']);
// => 3
 
_.get(object, 'a.b.c', 'default');
// => 'default'

Get of an unexisting property returns undefined or the default value, instead of throwing an error

Manipulate Objects

Work with properties

_.set()

var object = { 'a': [{ 'b': { 'c': 3 } }] };
 
_.set(object, 'a[0].b.c', 4);
console.log(object.a[0].b.c);
// => 4
 
_.set(object, ['x', '0', 'y', 'z'], 5);
console.log(object.x[0].y.z);
// => 5

If the path to set does not exist it is created, instead of throwing an error

Manipulate Objects

Work with properties

Check existence of a path: _.has()

var object = { 'a': { 'b': 2 } };
var other = _.create({ 'a': _.create({ 'b': 2 }) });
 
_.has(object, 'a');
// => true
 
_.has(object, 'a.b');
// => true
 
_.has(object, ['a', 'b']);
// => true
 
_.has(other, 'a');
// => false

Manipulate Objects

Merge objects

Normal merging of only own properties: _.assign()

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 }

Existing properties of the first object are overwritten from left to right

Manipulate Objects

Merge objects

Merging of own and inherited properties without overwriting: _.defaults()

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

The first object is considered the defaults. Only the properties that are not defined on it will be overwritten

Other gems

Other gems

Iterate a number of times

_.times(n, [iteratee=_.identity])

// 1. Basic for loop.
for(var i = 0; i < 5; i++) {
    // ....
}

// 2. Using Array's join and split methods
Array.apply(null, Array(5)).forEach(function(){
    // ...
});

// Lodash
_.times(5, function(){
    // ...
});

Other gems

Debouncing (delay execution of a function)

_.debounce(func, [wait=0], [options={}])

$(window)
    .on('scroll', _.debounce(scrollFunc, 1000));

scrollFunc will not be called until 1 second after scrolling has completed.

Other gems

Remove tildes, accents, etc... From a string

_.deburr([string=''])

_.deburr('déjà vu');
// => 'deja vu'

Removes all “combining diacritical marks”. 'Rubén' becomes 'Ruben'.

Great for sorting/searching.

Other gems

Deep clone

_.cloneDeep(value)

var objects = [{ 'a': 1 }, { 'b': 2 }];
 
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false

Functions to do this in plain JS are messy and/or hacky:

var cloned = JSON.parse(JSON.stringify(objectToClone));

Other gems

Math methods

_.maxBy(array, [iteratee=_.identity])

var objects = [{ 'n': 1 }, { 'n': 2 }];

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

_.meanBy(array, [iteratee=_.identity])

var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];

_.meanBy(objects, 'n');
// => 5

_.sumBy(array)

var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];

_.sumBy(objects, 'n');
// => 20

Questions?

Okay... I think it's enough, much more in https://lodash.com/docs/

Lodash introduction

By Hector Pablos

Lodash introduction

  • 1,749