lodash, underscore, ramda, and deepdash are JavaScript utility libraries designed to simplify common programming tasks involving arrays, objects, and functions. lodash is the modern industry standard for modular utility functions, offering a vast API for data manipulation. underscore is the legacy predecessor to lodash, now in maintenance mode but still found in older codebases. ramda focuses on functional programming with immutable data and automatic currying. deepdash specializes in deep object manipulation, often working alongside lodash to handle nested structures more effectively.
When building JavaScript applications, developers often need helper functions for arrays, objects, and common data tasks. lodash, underscore, ramda, and deepdash all solve this problem, but they approach it differently. Let's compare how they handle real-world engineering scenarios.
Accessing nested properties safely without causing crashes is a daily task. Each library offers a way to dig into objects without throwing errors if a key is missing.
lodash provides _.get, which allows you to specify a default value if the path does not exist.
// lodash
import get from 'lodash/get';
const user = { profile: { name: 'Alice' } };
const name = get(user, 'profile.name', 'Guest');
// Returns 'Alice'
ramda uses R.path for arrays of keys or R.prop for single keys. It is immutable and functional.
// ramda
import * as R from 'ramda';
const user = { profile: { name: 'Alice' } };
const name = R.path(['profile', 'name'], user) || 'Guest';
// Returns 'Alice'
underscore added _.get in later versions (1.13+), but older code often uses _.property.
// underscore
import _ from 'underscore';
const user = { profile: { name: 'Alice' } };
const name = _.get(user, 'profile.name', 'Guest');
// Returns 'Alice'
deepdash often works with lodash but focuses on deeper structures. It supports similar paths but emphasizes deep traversal.
// deepdash
import { get } from 'deepdash';
const user = { profile: { name: 'Alice' } };
const name = get(user, 'profile.name', 'Guest');
// Returns 'Alice'
How you combine or copy data changes based on whether you want to change the original object or create a new one.
lodash offers _.merge which mutates the first object by default. You must clone first if you want immutability.
// lodash
import _ from 'lodash';
const target = { a: 1 };
const source = { b: 2 };
_.merge(target, source);
// target is now { a: 1, b: 2 }
ramda functions are immutable by default. R.mergeDeep returns a new object without changing the inputs.
// ramda
import * as R from 'ramda';
const target = { a: 1 };
const source = { b: 2 };
const result = R.mergeDeep(target, source);
// target remains { a: 1 }, result is { a: 1, b: 2 }
underscore uses _.extend which is mutable, similar to lodash's merge behavior.
// underscore
import _ from 'underscore';
const target = { a: 1 };
const source = { b: 2 };
_.extend(target, source);
// target is now { a: 1, b: 2 }
deepdash specializes here. It provides _.merge that handles deep structures more intuitively and often supports immutable options or deep cloning out of the box.
// deepdash
import { merge } from 'deepdash';
const target = { a: 1 };
const source = { b: 2 };
const result = merge(target, source);
// Handles deep nesting better than standard lodash merge
This is where ramda separates itself from the others. It is built for function composition, while lodash and underscore are more utility-focused.
lodash supports chaining but functions are not curried by default. You often need _.curry explicitly.
// lodash
import _ from 'lodash';
const add = (a, b) => a + b;
const curriedAdd = _.curry(add);
const add5 = curriedAdd(5);
console.log(add5(10)); // 15
ramda curries every function automatically. This makes partial application very easy and natural.
// ramda
import * as R from 'ramda';
const add = R.add;
const add5 = add(5);
console.log(add5(10)); // 15
underscore does not support currying out of the box. You must write wrappers or use external helpers.
// underscore
import _ from 'underscore';
// No built-in curry, must implement manually or use _.partial
const add = (a, b) => a + b;
const add5 = _.partial(add, 5);
console.log(add5(10)); // 15
deepdash inherits lodash behavior but adds deep iteration methods that can be composed. It is less about currying and more about deep data traversal.
// deepdash
import { map } from 'deepdash';
// Focuses on deep mapping over nested structures
const data = { a: { b: 1 } };
const result = map(data, (val) => val * 2);
// Traverses deep into nested objects
Choosing a library also means choosing its future. You want tools that will be supported when bugs appear.
lodash is the industry standard. It is stable, widely used, and receives security patches regularly. It is safe for long-term projects.
// lodash
// Active maintenance, modular imports reduce bundle size
import map from 'lodash/map';
ramda has a dedicated community focused on functional programming. It is stable but changes less frequently because the API is mathematically grounded.
// ramda
// Stable functional API, less frequent breaking changes
import * as R from 'ramda';
underscore is in maintenance mode. It is not deprecated, but new features are rare. It is best for legacy support.
// underscore
// Legacy support, slow development cycle
import _ from 'underscore';
deepdash is active but niche. It depends on the health of lodash since it often wraps it. Good for specific deep data needs.
// deepdash
// Niche utility, extends lodash capabilities
import { cloneDeep } from 'deepdash';
| Feature | lodash | ramda | underscore | deepdash |
|---|---|---|---|---|
| Data Safety | ✅ _.get | ✅ R.path | ✅ _.get (new) | ✅ get |
| Immutability | ❌ Mutable default | ✅ Immutable default | ❌ Mutable default | ⚠️ Mixed |
| Currying | ⚠️ Manual | ✅ Automatic | ❌ None | ⚠️ Inherited |
| Deep Ops | ⚠️ Basic | ✅ Deep Merge | ❌ Limited | ✅ Specialized |
| Status | 🟢 Active | 🟢 Active | 🟡 Maintenance | 🟢 Active |
lodash is the reliable workhorse 🐴 — perfect for teams that need a vast set of tools without strict functional rules. It fits almost anywhere.
ramda is the functional specialist 🧙 — ideal for teams committed to immutable data and clean function pipelines. It requires a shift in thinking.
underscore is the legacy veteran 📜 — keep it if you have old code, but plan to migrate. Do not start new projects with it.
deepdash is the deep data expert 🕵️ — use it when lodash isn't enough for nested objects. It fills specific gaps.
Final Thought: For most modern frontend teams, lodash offers the best balance of features and support. If you love functional programming, ramda is worth the learning cost. Use deepdash only if you have complex nested data needs that lodash cannot handle cleanly.
Choose deepdash if your project heavily relies on nested object manipulation like deep merging or cloning where standard lodash methods fall short. It is best used alongside lodash to extend its capabilities for complex data structures. This package is ideal when you need reliable deep operations without writing recursive helpers yourself. However, remember it is often a wrapper, so consider the added dependency weight.
Choose lodash if you need a reliable, battle-tested utility library with a massive ecosystem and modular imports. It is the safest bet for most teams because of its stability and widespread adoption across the industry. Use it when you want a mix of functional and imperative styles without strict immutability requirements. It fits well in both legacy and modern JavaScript projects.
Choose ramda if your team embraces functional programming and wants immutable data operations by default. It is suitable for projects where data flow clarity and function composition are higher priorities than raw performance. The automatic currying makes it powerful for building reusable utility pipelines. Be aware that the learning curve is steeper for developers unfamiliar with functional concepts.
Choose underscore only if you are maintaining a legacy codebase that already depends on it heavily. It is not recommended for new projects because development has slowed significantly compared to lodash. While still functional, it lacks some modern optimizations and modular features found in newer libraries. Migrating to lodash is often a better long-term strategy for active projects.
eachDeep, filterDeep, findDeep, someDeep, omitDeep, pickDeep, keysDeep etc.. Tree traversal library written in Underscore/Lodash fashion. Standalone or as a Lodash mixin extension
Deepdash lib is used in PlanZed.org - awesome cloud mind map app created by the author of deepdash.
Plz check it, it's free and I need feedback 😉
Load script after Lodash, then pass a lodash instance to the deepdash function:
<script src="https://cdn.jsdelivr.net/npm/lodash/lodash.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/deepdash/browser/deepdash.min.js"></script>
<script>
deepdash(_);
console.log(_.eachDeep); // --> new methods mixed into Lodash
</script>
If you don't use Lodash - there is a standalone version:
<script src="https://cdn.jsdelivr.net/npm/deepdash/browser/deepdash.standalone.min.js"></script>
<script>
console.log(deepdash.eachDeep); // --> all the methods just work
</script>
Standalone Deepdash weighs more then "dry" version, because it includes some of cherry-picked Lodash methods it depends on. But it's better to use Standalone version, than include full Lodash just as dependency, if you don't need Lodash.
npm i --save deepdash
In Node.js:
// load Lodash if you need it
const _ = require('lodash');
//mixin all the methods into Lodash object
require('deepdash')(_);
// or cherry-pick method you only need and mix it into lodash
require('deepdash/addFilterDeep')(_);
// or cherry-pick method separately if you don't want to mutate Lodash instance
const filterDeep = require('deepdash/getFilterDeep')(_);
// If you don't need Lodash - there is standalone version
const deepdash = require('deepdash/standalone'); // full
const filterDeep = require('deepdash/filterDeep'); // or separate standalone methods
There is also deepdash as ES6 module
npm i --save deepdash-es
import lodash from 'lodash-es';
import deepdash from 'deepdash-es';
const _ = deepdash(lodash);
in the ES package there are same cherry-pick and/or standalone methods as in the main package.
import filterDeep from 'deepdash-es/filterDeep';
or
import { filterDeep } from 'deepdash-es/standalone';
or
import _ from 'lodash-es';
import getFilterDeep from 'deepdash-es/getFilterDeep';
const filterDeep = getFilterDeep(_);
or
import _ from 'lodash-es';
import addFilterDeep from 'deepdash-es/addFilterDeep';
addFilterDeep(_);// --> _.filterDeep
Example react+redux app with nested comments filtered by Deepdash.(source is here)
› iterate over all the children and sub-children 📚 see docs
let children = [
{
description: 'description for node 1',
comment: 'comment for node 1',
note: 'note for node 1',
name: 'node 1',
bad: false,
children: [
{
description: 'description for node 1.1',
comment: 'comment for node 1.1',
note: 'note for node 1.1',
name: 'node 1.1',
bad: false,
},
{
description: 'description for node 1.2',
comment: 'comment for node 1.2',
note: 'note for node 1.2',
name: 'node 1.2',
good: true,
},
{
description: 'description for node 1.3',
comment: 'comment for node 1.3',
note: 'note for node 1.3',
name: 'node 1.3',
bad: true,
good: false,
},
],
},
{
description: 'description for node 2',
comment: 'comment for node 2',
note: 'note for node 2',
name: 'node 2',
good: true,
children: [
{
description: 'description for node 2.1',
comment: 'comment for node 2.1',
note: 'note for node 2.1',
name: 'node 2.1',
bad: false,
},
{
description: 'description for node 2.2',
comment: 'comment for node 2.2',
note: 'note for node 2.2',
name: 'node 2.2',
good: true,
},
{
description: 'description for node 2.3',
comment: 'comment for node 2.3',
note: 'note for node 2.3',
name: 'node 2.3',
bad: true,
good: false,
},
],
},
{
description: 'description for node 3',
comment: 'comment for node 3',
note: 'note for node 3',
name: 'node 3',
bad: true,
good: false,
children: [
{
description: 'description for node 3.1',
comment: 'comment for node 3.1',
note: 'note for node 3.1',
name: 'node 3.1',
bad: false,
},
{
description: 'description for node 3.2',
comment: 'comment for node 3.2',
note: 'note for node 3.2',
name: 'node 3.2',
good: true,
},
{
description: 'description for node 3.3',
comment: 'comment for node 3.3',
note: 'note for node 3.3',
name: 'node 3.3',
bad: true,
good: false,
},
],
},
];
function displayField(val, key, parent, context) {
if (_.isArray(parent)) {
key = '[' + key + ']';
}
console.log(
_.repeat(' ', context.depth) +
'→ ' +
key +
': ' +
(_.isArray(val)
? '[' + val.length + ']'
: _.isObject(val)
? '{' + (val.name || '') + '}'
: val)
);
}
console.log('\n = Iterate over tree (each child object) = \n');
_.eachDeep(children, displayField, { childrenPath: 'children' });
console.log('\n = Iterate over object (each field) = \n');
_.eachDeep(children, displayField);
= Iterate over tree (each child object) =
→ [0]: {node 1}
→ [0]: {node 1.1}
→ [1]: {node 1.2}
→ [2]: {node 1.3}
→ [1]: {node 2}
→ [0]: {node 2.1}
→ [1]: {node 2.2}
→ [2]: {node 2.3}
→ [2]: {node 3}
→ [0]: {node 3.1}
→ [1]: {node 3.2}
→ [2]: {node 3.3}
= Iterate over object (each field) =
→ [0]: {node 1}
→ description: description for node 1
→ comment: comment for node 1
→ note: note for node 1
→ name: node 1
→ bad: false
→ children: [3]
→ [0]: {node 1.1}
→ description: description for node 1.1
→ comment: comment for node 1.1
→ note: note for node 1.1
→ name: node 1.1
→ bad: false
→ [1]: {node 1.2}
→ description: description for node 1.2
→ comment: comment for node 1.2
→ note: note for node 1.2
→ name: node 1.2
→ good: true
→ [2]: {node 1.3}
→ description: description for node 1.3
→ comment: comment for node 1.3
→ note: note for node 1.3
→ name: node 1.3
→ bad: true
→ good: false
→ [1]: {node 2}
→ description: description for node 2
→ comment: comment for node 2
→ note: note for node 2
→ name: node 2
→ good: true
→ children: [3]
→ [0]: {node 2.1}
→ description: description for node 2.1
→ comment: comment for node 2.1
→ note: note for node 2.1
→ name: node 2.1
→ bad: false
→ [1]: {node 2.2}
→ description: description for node 2.2
→ comment: comment for node 2.2
→ note: note for node 2.2
→ name: node 2.2
→ good: true
→ [2]: {node 2.3}
→ description: description for node 2.3
→ comment: comment for node 2.3
→ note: note for node 2.3
→ name: node 2.3
→ bad: true
→ good: false
→ [2]: {node 3}
→ description: description for node 3
→ comment: comment for node 3
→ note: note for node 3
→ name: node 3
→ bad: true
→ good: false
→ children: [3]
→ [0]: {node 3.1}
→ description: description for node 3.1
→ comment: comment for node 3.1
→ note: note for node 3.1
→ name: node 3.1
→ bad: false
→ [1]: {node 3.2}
→ description: description for node 3.2
→ comment: comment for node 3.2
→ note: note for node 3.2
→ name: node 3.2
→ good: true
→ [2]: {node 3.3}
→ description: description for node 3.3
→ comment: comment for node 3.3
→ note: note for node 3.3
→ name: node 3.3
→ bad: true
→ good: false
› deep filter object 📚 see docs
let children = [
{
description: 'description for node 1',
comment: 'comment for node 1',
note: 'note for node 1',
name: 'node 1',
bad: false,
children: [
{
description: 'description for node 1.1',
comment: 'comment for node 1.1',
note: 'note for node 1.1',
name: 'node 1.1',
bad: false,
},
{
description: 'description for node 1.2',
comment: 'comment for node 1.2',
note: 'note for node 1.2',
name: 'node 1.2',
good: true,
},
{
description: 'description for node 1.3',
comment: 'comment for node 1.3',
note: 'note for node 1.3',
name: 'node 1.3',
bad: true,
good: false,
},
],
},
{
description: 'description for node 2',
comment: 'comment for node 2',
note: 'note for node 2',
name: 'node 2',
good: true,
children: [
{
description: 'description for node 2.1',
comment: 'comment for node 2.1',
note: 'note for node 2.1',
name: 'node 2.1',
bad: false,
},
{
description: 'description for node 2.2',
comment: 'comment for node 2.2',
note: 'note for node 2.2',
name: 'node 2.2',
good: true,
},
{
description: 'description for node 2.3',
comment: 'comment for node 2.3',
note: 'note for node 2.3',
name: 'node 2.3',
bad: true,
good: false,
},
],
},
{
description: 'description for node 3',
comment: 'comment for node 3',
note: 'note for node 3',
name: 'node 3',
bad: true,
good: false,
children: [
{
description: 'description for node 3.1',
comment: 'comment for node 3.1',
note: 'note for node 3.1',
name: 'node 3.1',
bad: false,
},
{
description: 'description for node 3.2',
comment: 'comment for node 3.2',
note: 'note for node 3.2',
name: 'node 3.2',
good: true,
},
{
description: 'description for node 3.3',
comment: 'comment for node 3.3',
note: 'note for node 3.3',
name: 'node 3.3',
bad: true,
good: false,
},
],
},
];
console.log('\n = Filter tree (good children) = \n');
console.log(
_.filterDeep(children, 'good', { childrenPath: 'children' })
);
console.log('\n = Filter object (names of good children) = \n');
console.log(
_.filterDeep(children, (val, key, parent) => {
if (key == 'name' && parent.good) return true;
})
);
= Filter tree (good children) =
[
{
"description": "description for node 1",
"comment": "comment for node 1",
"note": "note for node 1",
"name": "node 1",
"bad": false,
"children": [
{
"description": "description for node 1.2",
"comment": "comment for node 1.2",
"note": "note for node 1.2",
"name": "node 1.2",
"good": true
}
]
},
{
"description": "description for node 2",
"comment": "comment for node 2",
"note": "note for node 2",
"name": "node 2",
"good": true,
"children": [
{
"description": "description for node 2.2",
"comment": "comment for node 2.2",
"note": "note for node 2.2",
"name": "node 2.2",
"good": true
}
]
},
{
"description": "description for node 3",
"comment": "comment for node 3",
"note": "note for node 3",
"name": "node 3",
"bad": true,
"good": false,
"children": [
{
"description": "description for node 3.2",
"comment": "comment for node 3.2",
"note": "note for node 3.2",
"name": "node 3.2",
"good": true
}
]
}
]
= Filter object (names of good children) =
[
{
"children": [
{
"name": "node 1.2"
}
]
},
{
"name": "node 2",
"children": [
{
"name": "node 2.2"
}
]
},
{
"children": [
{
"name": "node 3.2"
}
]
}
]
› find first matching deep meta-value 📚 see docs
// next time
// sorry
❤️
› find first matching deep value 📚 see docs
// next time
// sorry
❤️
› find the path of the first matching deep value 📚 see docs
// next time
// sorry
❤️
› get array of values processed by iteratee. 📚 see docs
let res = _.mapDeep(
{ hello: { from: { the: 'deep world', and: 'deepdash' } } },
(v) => v.toUpperCase(),
{ leavesOnly: true }
);
// res -> ['DEEP WORLD','DEEPDASH']
› get the object with same structure, but transformed values. 📚 see docs
let res = _.mapValuesDeep(
{ hello: { from: { the: 'deep world' } } },
(v) => v.toUpperCase(),
{ leavesOnly: true }
);
// res -> { hello: { from: { the: 'DEEP WORLD' } } }
› get the object with same values, but transformed keys. 📚 see docs
let res = _.mapKeysDeep(
{ hello: { from: { the: 'deep world' } } },
(v, k) => k.toUpperCase()
);
// res -> { HELLO: { FROM: { THE: 'deep world' } } }
› like reduce, but deep 📚 see docs
let max = _.reduceDeep({ a: 2, b: 3, c: { d: 6, e: [1, 5, 8] } },
(acc, value, key, parent, ctx) => {
if (typeof value == 'number' && (typeof acc != 'number' || value > acc))
return value;
return undefined;
}
);
// max == 8
› returns true if some matching deep value found 📚 see docs
// next time
// sorry
❤️
› pick values by paths specified by endings or regexes 📚 see docs
let children = [
{
description: 'description for node 1',
comment: 'comment for node 1',
note: 'note for node 1',
name: 'node 1',
bad: false,
children: [
{
description: 'description for node 1.1',
comment: 'comment for node 1.1',
note: 'note for node 1.1',
name: 'node 1.1',
bad: false,
},
{
description: 'description for node 1.2',
comment: 'comment for node 1.2',
note: 'note for node 1.2',
name: 'node 1.2',
good: true,
},
{
description: 'description for node 1.3',
comment: 'comment for node 1.3',
note: 'note for node 1.3',
name: 'node 1.3',
bad: true,
good: false,
},
],
},
{
description: 'description for node 2',
comment: 'comment for node 2',
note: 'note for node 2',
name: 'node 2',
good: true,
children: [
{
description: 'description for node 2.1',
comment: 'comment for node 2.1',
note: 'note for node 2.1',
name: 'node 2.1',
bad: false,
},
{
description: 'description for node 2.2',
comment: 'comment for node 2.2',
note: 'note for node 2.2',
name: 'node 2.2',
good: true,
},
{
description: 'description for node 2.3',
comment: 'comment for node 2.3',
note: 'note for node 2.3',
name: 'node 2.3',
bad: true,
good: false,
},
],
},
{
description: 'description for node 3',
comment: 'comment for node 3',
note: 'note for node 3',
name: 'node 3',
bad: true,
good: false,
children: [
{
description: 'description for node 3.1',
comment: 'comment for node 3.1',
note: 'note for node 3.1',
name: 'node 3.1',
bad: false,
},
{
description: 'description for node 3.2',
comment: 'comment for node 3.2',
note: 'note for node 3.2',
name: 'node 3.2',
good: true,
},
{
description: 'description for node 3.3',
comment: 'comment for node 3.3',
note: 'note for node 3.3',
name: 'node 3.3',
bad: true,
good: false,
},
],
},
];
console.log('\n = Pick name and description only = \n');
console.log(
_.pickDeep(children, ['name', 'description'])
);
= Pick name and description only =
[
{
"description": "description for node 1",
"name": "node 1",
"children": [
{
"description": "description for node 1.1",
"name": "node 1.1"
},
{
"description": "description for node 1.2",
"name": "node 1.2"
},
{
"description": "description for node 1.3",
"name": "node 1.3"
}
]
},
{
"description": "description for node 2",
"name": "node 2",
"children": [
{
"description": "description for node 2.1",
"name": "node 2.1"
},
{
"description": "description for node 2.2",
"name": "node 2.2"
},
{
"description": "description for node 2.3",
"name": "node 2.3"
}
]
},
{
"description": "description for node 3",
"name": "node 3",
"children": [
{
"description": "description for node 3.1",
"name": "node 3.1"
},
{
"description": "description for node 3.2",
"name": "node 3.2"
},
{
"description": "description for node 3.3",
"name": "node 3.3"
}
]
}
]
› get object without paths specified by endings or regexes 📚 see docs
let children = [
{
description: 'description for node 1',
comment: 'comment for node 1',
note: 'note for node 1',
name: 'node 1',
bad: false,
children: [
{
description: 'description for node 1.1',
comment: 'comment for node 1.1',
note: 'note for node 1.1',
name: 'node 1.1',
bad: false,
},
{
description: 'description for node 1.2',
comment: 'comment for node 1.2',
note: 'note for node 1.2',
name: 'node 1.2',
good: true,
},
{
description: 'description for node 1.3',
comment: 'comment for node 1.3',
note: 'note for node 1.3',
name: 'node 1.3',
bad: true,
good: false,
},
],
},
{
description: 'description for node 2',
comment: 'comment for node 2',
note: 'note for node 2',
name: 'node 2',
good: true,
children: [
{
description: 'description for node 2.1',
comment: 'comment for node 2.1',
note: 'note for node 2.1',
name: 'node 2.1',
bad: false,
},
{
description: 'description for node 2.2',
comment: 'comment for node 2.2',
note: 'note for node 2.2',
name: 'node 2.2',
good: true,
},
{
description: 'description for node 2.3',
comment: 'comment for node 2.3',
note: 'note for node 2.3',
name: 'node 2.3',
bad: true,
good: false,
},
],
},
{
description: 'description for node 3',
comment: 'comment for node 3',
note: 'note for node 3',
name: 'node 3',
bad: true,
good: false,
children: [
{
description: 'description for node 3.1',
comment: 'comment for node 3.1',
note: 'note for node 3.1',
name: 'node 3.1',
bad: false,
},
{
description: 'description for node 3.2',
comment: 'comment for node 3.2',
note: 'note for node 3.2',
name: 'node 3.2',
good: true,
},
{
description: 'description for node 3.3',
comment: 'comment for node 3.3',
note: 'note for node 3.3',
name: 'node 3.3',
bad: true,
good: false,
},
],
},
];
console.log('\n = Omit paths not ending with "e" = \n');
console.log(
_.omitDeep(children, /[^e]$/i, { onMatch: { skipChildren: false } }),
);
= Omit paths not ending with "e" =
[
{
"note": "note for node 1",
"name": "node 1",
"children": [
{
"note": "note for node 1.1",
"name": "node 1.1"
},
{
"note": "note for node 1.2",
"name": "node 1.2"
},
{
"note": "note for node 1.3",
"name": "node 1.3"
}
]
},
{
"note": "note for node 2",
"name": "node 2",
"children": [
{
"note": "note for node 2.1",
"name": "node 2.1"
},
{
"note": "note for node 2.2",
"name": "node 2.2"
},
{
"note": "note for node 2.3",
"name": "node 2.3"
}
]
},
{
"note": "note for node 3",
"name": "node 3",
"children": [
{
"note": "note for node 3.1",
"name": "node 3.1"
},
{
"note": "note for node 3.2",
"name": "node 3.2"
},
{
"note": "note for node 3.3",
"name": "node 3.3"
}
]
}
]
› get an object with all the paths as keys and corresponding values 📚 see docs
let index = _.index(
{
a: {
b: {
c: [1, 2, 3],
'hello world': {},
},
},
},
{ leavesOnly: true }
);
console.log(index);
Console:
{ 'a.b.c[0]': 1,
'a.b.c[1]': 2,
'a.b.c[2]': 3,
'a.b["hello world"]': {} }
› get an array of paths 📚 see docs
let paths = _.paths(
{
a: {
b: {
c: [1, 2, 3],
'hello world': {},
},
},
},
{ leavesOnly: false }
);
console.log(paths);
Console:
[ 'a',
'a.b',
'a.b.c',
'a.b.c[0]',
'a.b.c[1]',
'a.b.c[2]',
'a.b["hello world"]' ]
› condense sparse array 📚 see docs
let arr = ['a', 'b', 'c', 'd', 'e'];
delete arr[1];
console.log(arr);
delete arr[3];
console.log(arr);
_.condense(arr);
console.log(arr);
Console:
[ 'a', <1 empty item>, 'c', 'd', 'e' ]
[ 'a', <1 empty item>, 'c', <1 empty item>, 'e' ]
[ 'a', 'c', 'e' ]
› condense all the nested arrays 📚 see docs
let obj = { arr: ['a', 'b', { c: [1, , 2, , 3] }, 'd', 'e'] };
delete obj.arr[1];
delete obj.arr[3];
_.condenseDeep(obj);
console.log(obj);
Console:
{ arr: [ 'a', { c: [ 1, 2, 3 ] }, 'e' ] }
› like a _.has but returns false for empty array slots 📚 see docs
var obj = [, { a: [, 'b'] }];
console.log(_.exists(obj, 0)); // false
console.log(_.exists(obj, 1)); // true
console.log(_.exists(obj, '[1].a[0]')); // false
console.log(_.exists(obj, '[1].a[1]')); // true
› convert an array to string path (opposite to _.toPath) 📚 see docs
console.log(_.pathToString(['a', 'b', 'c', 'defg', 0, '1', 2.3]
,'prefix1', 'prefix2', '[3]'));
// prefix1.prefix2[3].a.b.c.defg[0][1]["2.3"]
console.log(_.pathToString(['"', '"', '"']));
// ["\\""]["\\""]["\\""]
console.log(_.pathToString('it.s.a.string'));
// it.s.a.string
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!