LO-DASH
Lodash is an utility library designed for everyday use. This is the missing toolkit for Javascript to start being productive right away.
Lodash is for Javascript what jQuery is for DOM.
Example: map over an array
var arr = ["John", "Marc", "Louie"];
var result = [];
for (var i = 0; i < arr.length; i++) {
result.push(arr[i].toUpperCase());
}
return result;
var arr = ["John", "Marc", "Louie"];
return arr.map(function(name) {
return name.toUpperCase();
});
// What if arr is undefined ? Error
ES5.1 version
Old school version
With Lodash
var arr = ["John", "Marc", "Louie"];
return _.map(arr, _.method('toUpperCase'))
// If arr is undefined, it will return undefined
Lodash can map over any iterable
return _.map("Hello", function (letter) {
return letter + "-"
])
// return "H-e-l-l-o"
var obj = {name: "John", city: "Tel Aviv"}
return _.map(obj, function (key, value) {
var res = {};
res[key.toUpperCase()] = value.toLowerCase();
return res;
])
// return { NAME: "john", CITY: "tel aviv" }
Strings
Objects
Functional programming style
var arr = [{name: 'Foo'}, {name: 'Bar'}]
return _.map(arr, 'name')
// return ['Foo', 'Bar']
var arr = ["John", "Mike"]
return _.map(arr, _.method('toUpperCase'))
// return ["JOHN", "MIKE"]
Get the name property of a list of objects
Use with native functions
var arr = ["data_feeds", "first_name"]
return _.map(arr, _.toCamelCase)
// return ["dataFeeds", "firstName"]
Use with lodash functions
// Execute last then upperCase
var upperLast = _.compose(_.method('toUpperCase'), _.last)
upperLast(["John", "Mike", "Louie"];) // 'LOUIE'
// Partial right will bind the last argument of map (the callback)
// with the provided callback, here snakecase
var snakeCaseArray = _.partialRight(_.map, _.snakeCase)
snakeCaseArray(['I love boats', 'I love planes']) // ['i_love_boats', 'i_love_planes']
// Compose the compositions
var upperLastSnakeCase = _.compose(upperLast, snakeCaseArray)
upperLastSnakeCase(['I love boats', 'I love planes']); // 'I_LOVE_PLANES'
var array = [{name: 'John'}, {name: 'Mike'}, {name: 'Jim'}, 10]
_(array)
.filter(item => _.isObject(item))
.pluck('name')
.map(_.capitalize)
.groupBy(item => _.first(item))
.value()
// return { 'J': 2, 'M': 1 }
Manage models
function MyAngularService($http) {
function MyModel(data) {
// defaults
this.name = '';
this.description = '';
// Prefill with data
_.extend(this, data)
// strip out name from the label objects
this.labels = _.pluck(this.labels, 'name')
}
this.serialize = function (object) {
// Only send out the relevant fields
return _.pick(object, ['name', 'description', 'labels']);
}
}
Manage collections
function MyAngularController($scope, dataFeeds) {
$scope.dataFeeds = _(dataFeeds)
.compact()
.filter(dataFeed => dataFeed.isActive)
.sortBy('name')
.groupBy('status')
.value();
$scope.get = function (name) {
return _.where($scope.dataFeeds, {name: name})
}
$scope.delete = function (id) {
return _.remove($scope.dataFeeds, {id: id})
}
$scope.search = function (query) {
return _.filter($scope.dataFeeds, _.partialRight(_.contains, query))
}
$scope.refresh = function (newDataFeeds) {
return _.union($scope.dataFeeds, newDataFeeds)
}
}
Create filters
function removeDuplicates() {
return function(collection, property) {
return _.unique(collection, property);
}
}
function camelCaseKeys() {
return function(object) {
return _.mapKeys(object, (v, k) => _.camelCase(k));
}
}
<div ng-repeat="item in items | removeDuplicates:'name'">{{ item }}</div>
<pre>{{ item | camelCaseKeys | json }}</pre>
Example: pagination
<div ng-repeat='user in users | slice:(page * amountPerPage):((page + 1) * amountPerPage)'>
{{user.name | capitalize }}
</div>
<button ng-click='page = page - 1'>Previous</button>
<span>Page {{ page }} of {{ users | size }}</span>
<button ng-click='page = page + 1'>Next</button>
Application: debouncing watchers
// The watcher function will be triggered only once every 1000 ms
$scope.$watch('property', _.debounce(function(newVal, oldVal) {
// do something
}, 1000));
Application: Run once watchers
// The watcher function will be triggered only once
$scope.$watch('property', _.once(function(newVal, oldVal) {
// do something
}, 1000));
Application: Getting a heavily nested property
// Before
function getFirstDataFeedTemplateName(dfs) {
return dfs && dfs[0] && dfs[0].template && dfs[0].template.name;
}
allNames = allNames.map(function(df) {
return df && df.template && df.template.name;
})
// After
function getFirstDataFeedTemplateName(dfs) {
return _.get(dfs, '[0].template.name')
}
allNames = _.map(dfs, _.property('template.name'))
Application: Replace for loops
// Before
var objects = [];
for (var i = 0; i < 100; i++) {
objects.push(new MyObject());
}
// After
var objects = _.range(100).map(i => new MyObject());
Application: Interpolate strings
// Before
var myData = {name: 'Foo'}
var myString = 'My name is ' + myData.name + '!';
// After
var myString = _.template('My name is <%= name %>!')(myData)
// PS: ES2015 template strings are way better