Skip to content
Lodash Utilities — Strings, Math, Type Checks & Performance Optimization

Lodash Utilities — Strings, Math, Type Checks & Performance Optimization

DodaTech Updated Jun 6, 2026 16 min read

Lodash utility functions handle string conversion, math helpers, type checks, and templating — the everyday JavaScript tasks that native code does not simplify.

What You’ll Learn

  • String utilities: _.camelCase, _.kebabCase, _.snakeCase, _.escape, _.unescape, _.template, _.truncate
  • Math utilities: _.random, _.range, _.clamp, _.inRange, _.round
  • Type checking: _.isArray, _.isPlainObject, _.isEqual, _.isEmpty, _.isNil
  • Lazy evaluation with _.chain() + .commit(), _.thru, _.iteratee

Why Utility Functions Matter

The difference between a good developer and a great one often comes down to tooling knowledge. String manipulation, type checking, and math helpers seem mundane — until you have to generate 10,000 sequential IDs, safely compare deeply nested objects, or handle user input that could contain XSS vectors.

In Durga Antivirus Pro, _.escape sanitizes file paths and user-generated scan names before rendering. _.camelCase and _.kebabCase normalize threat category names from various threat intelligence feeds. _.isEqual deep-compares configuration snapshots to detect unauthorized changes. And _.range generates paginated lists of scan results efficiently.

Learning Path

    flowchart LR
  A["Objects &<br/>Functions"] --> B["Utilities &<br/>Performance"]
  B --> C["Real Project:<br/>String Studio"]
  B --> D["Next Topic:<br/>Axios"]
  style B fill:#38bdf8,color:#0f172a,stroke:#38bdf8,stroke-width:2px
  style C fill:#22c55e,color:#0f172a
  
Complete https://tutorials.dodatech.com/frontend/libraries/lodash/lodash-objects-functions/ first. You should understand JavaScript basics: strings, numbers, typeof, instanceof, and the concept of truthy/falsy values.

String Utilities

Lodash string methods handle edge cases that native JavaScript string methods don’t: accented characters, Unicode normalization, mixed-case inputs, and special characters.

_.camelCase, _.kebabCase, _.snakeCase, _.startCase

These convert between naming conventions — essential when your API returns snake_case but your JavaScript code uses camelCase:

import camelCase from 'lodash/camelCase';
import kebabCase from 'lodash/kebabCase';
import snakeCase from 'lodash/snakeCase';
import startCase from 'lodash/startCase';

// camelCase — used in JavaScript variables and functions
camelCase('Foo Bar');        // 'fooBar'
camelCase('--foo-bar--');    // 'fooBar'
camelCase('__FOO_BAR__');    // 'fooBar'

// kebabCase — used in URLs and CSS classes
kebabCase('Foo Bar');        // 'foo-bar'
kebabCase('camelCase');      // 'camel-case'

// snakeCase — used in database columns and Python
snakeCase('Foo Bar');        // 'foo_bar'

// startCase — used for human-readable titles
startCase('fooBar');         // 'Foo Bar'

Why not just use .toLowerCase().replace(/ /g, '-')? Because that naive approach breaks on edge cases like '--foo-bar--' (double hyphens), '__FOO_BAR__' (underscores), and 'camelCase' (no spaces). Lodash handles all of these correctly.

_.escape and _.unescape — HTML Sanitization

These protect against XSS (Cross-Site Scripting) attacks by converting HTML special characters to their entity equivalents:

import escape from 'lodash/escape';
import unescape from 'lodash/unescape';

escape('<script>alert("xss")</script>');
// '&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;'

unescape('&lt;tag&gt;');
// '<tag>'

When to use: Always escape user-generated content before inserting it into HTML. Even if you use a framework like React that handles most escaping, _.escape is useful for server-rendered content or raw HTML templates.

_.template — JavaScript Template Engine

_.template compiles a string with embedded expressions into a reusable function. Think of it as mail merge for code:

import template from 'lodash/template';

// Step 1: Compile the template into a function
const compiled = template('<h1><%= title %></h1><p><%= message %></p>');

// Step 2: Execute with data
const html = compiled({ title: 'Hello', message: 'World' });
// '<h1>Hello</h1><p>World</p>'

Three delimiter types:

DelimiterBehaviorUse Case
<%= %>Interpolate (plain)Output values as-is
<%- %>Interpolate (escaped)Auto-escape HTML
<% %>Execute JavaScriptLoops, conditionals
// Escaped output — safe for user input
const safe = template('<p><%- userInput %></p>');
safe({ userInput: '<script>alert(1)</script>' });
// '<p>&lt;script&gt;alert(1)&lt;/script&gt;</p>'

// With loops
const list = template('<ul><% items.forEach(function(item) { %><li><%= item %></li><% }); %></ul>');
list({ items: ['a', 'b', 'c'] });
// '<ul><li>a</li><li>b</li><li>c</li></ul>'

_.truncate — Cut Text to Length

Truncates a string to a maximum length, adding an omission suffix:

import truncate from 'lodash/truncate';

truncate('The quick brown fox jumps over the lazy dog', { length: 20 });
// 'The quick brown fox...'

truncate('Short text', { length: 30 });
// 'Short text' — no truncation needed

// Custom omission
truncate('Long text that needs to be cut off', {
  length: 15,
  omission: '... (more)'
});
// 'Long text... (more)'

// Word-boundary aware
truncate('The quick brown fox', {
  length: 12,
  separator: /\s+/
});
// 'The quick...'

Other String Helpers

import pad from 'lodash/pad';
import repeat from 'lodash/repeat';
import startsWith from 'lodash/startsWith';

pad('abc', 8);             // '  abc   '
pad('abc', 8, '_-');       // '_-abc_-_'
repeat('*', 5);            // '*****'
startsWith('hello', 'he'); // true

Math Utilities

_.random — Generate Random Numbers

import random from 'lodash/random';

random(0, 10);          // Random integer between 0 and 10 (inclusive)
random(5);              // Random integer between 0 and 5
random(0, 10, true);    // Random FLOAT between 0 and 10

Without the third argument (true), the result is always an integer. Pass true for floating-point.

_.range — Create Sequential Arrays

Think of _.range as a number-line generator — perfect for loops, pagination, and test data:

import range from 'lodash/range';

range(4);               // [0, 1, 2, 3]
range(1, 5);            // [1, 2, 3, 4]
range(0, 20, 5);        // [0, 5, 10, 15]
range(0, -4, -1);       // [0, -1, -2, -3]

_.clamp and _.inRange — Bounds Checking

_.clamp constrains a value between a minimum and maximum — like a volume slider that can’t go below 0 or above 100:

import clamp from 'lodash/clamp';
import inRange from 'lodash/inRange';

clamp(-10, -5, 5);      // -5 (brought up to minimum)
clamp(10, -5, 5);       // 5 (brought down to maximum)
clamp(3, -5, 5);        // 3 (stays unchanged)

inRange(3, 2, 4);       // true (2 <= 3 < 4)
inRange(4, 8);          // true (0 <= 4 < 8 — start defaults to 0)

_.round, _.floor, _.ceil — Precision Rounding

import round from 'lodash/round';
import floor from 'lodash/floor';
import ceil from 'lodash/ceil';

round(4.006);            // 4
round(4.006, 2);         // 4.01
round(4160, -2);         // 4200 (rounds to nearest hundred)
floor(4.006, 2);         // 4
ceil(4.006, 2);          // 4.01

Type Checking

Why Lodash Type Checks?

JavaScript’s typeof operator has well-known pitfalls: typeof null returns 'object', typeof [] returns 'object', and typeof can’t distinguish between different object types. Lodash type-checking methods are reliable across environments, including cross-frame scenarios where instanceof fails.

_.isArray, _.isPlainObject

import isArray from 'lodash/isArray';
import isPlainObject from 'lodash/isPlainObject';

isArray([]);               // true
isArray(new Array(5));     // true
isArray({});               // false

isPlainObject({});              // true
isPlainObject(new Object());    // true
isPlainObject(new Date());      // false
isPlainObject(Object.create(null)); // true

_.isEqual — Deep Comparison

This is one of the most useful Lodash methods. It performs a deep comparison between two values — recursively checking every nested property:

import isEqual from 'lodash/isEqual';

isEqual({ a: 1, b: { c: 2 } }, { a: 1, b: { c: 2 } });
// true — deeply equal

isEqual([1, 2, 3], [1, 2, 3]);
// true

isEqual(new Date(2023, 0, 1), new Date(2023, 0, 1));
// true — Date objects compared by value

isEqual(NaN, NaN);
// true — NaN equals NaN (unlike === which says false)

_.isEmpty

Checks if a value is “empty” — works across collections, strings, maps, and sets:

import isEmpty from 'lodash/isEmpty';

isEmpty(null);              // true
isEmpty(undefined);         // true
isEmpty('');                // true
isEmpty([]);                // true
isEmpty({});                // true
isEmpty(new Map());         // true
isEmpty(new Set());         // true
isEmpty('hello');           // false
isEmpty([1]);               // false
isEmpty({ a: 1 });          // false
_.isEmpty(0) returns true, and _.isEmpty(true) returns true. These are primitives that have no enumerable properties, so Lodash considers them “empty.” If you need to check for null/undefined specifically, use _.isNil.

_.isNil and Other Checks

import isNil from 'lodash/isNil';
import isNull from 'lodash/isNull';
import isUndefined from 'lodash/isUndefined';
import isFunction from 'lodash/isFunction';
import isString from 'lodash/isString';
import isNumber from 'lodash/isNumber';
import isDate from 'lodash/isDate';
import isRegExp from 'lodash/isRegExp';

isNil(null);        // true
isNil(undefined);   // true
isNil(0);           // false

Performance & Lazy Evaluation

How Lazy Evaluation Works

You learned about _.chain() in the Getting Started guide. Here’s the deeper performance story:

Without chaining, each Lodash method creates an intermediate array that gets passed to the next method:

// Eager evaluation — three passes over the data
const filtered = _.filter(data, n => n % 2 === 0);  // Pass 1
const mapped = _.map(filtered, n => n * 3);          // Pass 2
const result = _.take(mapped, 10);                    // Pass 3

With chaining, Lodash uses lazy evaluation. It doesn’t execute anything until .value() is called. At that point, it can reorder operations for maximum efficiency:

// Lazy evaluation — single pass
const result = _.chain(data)
  .filter(n => n % 2 === 0)
  .map(n => n * 3)
  .take(10)
  .value();

Lodash internally recognizes that _.take(10) means we only need 10 results. So it pushes the filter and map operations to only process enough elements to produce 10 outputs. On a million-element array, this processes ~20 elements instead of 1,000,000.

_.commit() — Split a Chain

_.commit() forces the chain to execute intermediate steps and return a wrapped result, allowing you to split a long pipeline:

const players = [
  { name: 'Alice', score: 90 },
  { name: 'Bob', score: 70 },
  { name: 'Charlie', score: 95 },
];

const wrapped = _.chain(players)
  .filter(p => p.score > 80)
  .commit(); // Executes filter, returns new wrapper

// Continue chaining on the filtered subset
wrapped.map('name').value();
// ['Alice', 'Charlie']

_.thru — Inject Custom Logic

Pass the intermediate value through any function in the middle of a chain:

const result = _.chain([1, 2, 3, 4])
  .map(n => n * 2)
  .thru(arr => arr.join(':'))
  .value();
// '2:4:6:8'

_.iteratee — The Engine Behind Shorthands

Every time you pass a string like 'name' or an object like { active: true } to a Lodash method, _.iteratee converts it into a function behind the scenes:

import iteratee from 'lodash/iteratee';

// Property name → function that extracts that property
iteratee('name')({ name: 'Alice' });            // 'Alice'

// Property path → function that extracts deeply
iteratee('address.city')({ address: { city: 'NYC' } }); // 'NYC'

// Object match → function that checks partial match
iteratee({ active: true })({ active: true, age: 25 });  // true

// Function → passthrough (no conversion needed)
iteratee(n => n * 2)(5);                                 // 10

Common Mistakes

1. Using _.isEmpty with Numbers or Booleans

// These are probably not what you expect:
_.isEmpty(0);        // true
_.isEmpty(true);     // true
_.isEmpty('false');  // false (has length 5)

// Use _.isNil for null/undefined checks
// Use _.isNumber for number checks

2. Forgetting _.template Returns a Function

// ❌ Tries to render immediately — returns a function, not a string
const html = template('<%= name %>', { name: 'Alice' });

// ✅ Compile first, then execute
const compiled = template('<%= name %>');
const html = compiled({ name: 'Alice' });

3. Not Understanding _.random Return Types

random(0, 10);         // Integer (default behavior)
random(0, 10, true);   // Float

If you need 2 decimal places, chain with _.round:

_.round(_.random(0, 10, true), 2);

4. Naive String Replacement Instead of Case Conversion

// ❌ Breaks on edge cases
'FOO_BAR'.toLowerCase().replace(/_/g, '-'); // 'foo-bar' — OK but...

// ❌ What about camelCase input?
'fooBar'.toLowerCase().replace(/_/g, '-'); // 'foobar' — lost the capital B!

// ✅ Lodash handles everything
_.kebabCase('fooBar'); // 'foo-bar'

5. Using Lazy Chaining on Tiny Datasets

For arrays with fewer than ~100 elements, the overhead of building a chain wrapper exceeds any performance benefit. Use direct method calls or native methods for small data.

Practice Questions

1. What does _.kebabCase('helloWorld') return?

Answer: 'hello-world'. It detects the capital W and inserts a hyphen.

2. Why is _.isEqual(NaN, NaN) true when NaN === NaN is false?

Answer: JavaScript’s === considers NaN not equal to anything (per IEEE 754). _.isEqual uses the SameValueZero algorithm which treats NaN as equal to itself, making it more useful for deep comparison.

3. What is the difference between <%= %> and <%- %> in _.template?

Answer: <%= %> outputs the value as-is (no escaping). <%- %> HTML-escapes the output. Use <%- %> for user-generated content to prevent XSS.

4. How does lazy evaluation improve performance in _.chain()?

Answer: Lazy evaluation defers computation until .value() is called, allowing Lodash to reorder operations (e.g., pushing _.take(10) earlier) so filter/map only process the minimum elements needed instead of the entire collection.

Challenge

Build a URL slug generator using Lodash utilities: start with 'My Durga Antivirus Scan Report: Results for 2024!', convert it to a URL-safe slug, truncate it to 30 characters (without breaking mid-word), and output the final slug. Expected approach: _.kebabCase_.truncate with word-boundary separator. Verify the result starts with 'my-durga-antivirus-scan'.

FAQ

What is the difference between _.template and JavaScript template literals?

_.template compiles reusable templates with embedded logic (<% %> loops, conditionals), supports HTML escaping (<%- %>), and can be pre-compiled for performance. Template literals are evaluated immediately and don’t support logic blocks or auto-escaping.

Does _.isEqual handle circular references?

Yes. _.isEqual can deeply compare objects with circular references without throwing.

When should I use _.commit() in a chain?

Use _.commit() when you want to break a long pipeline into phases, reusing an intermediate result for multiple downstream transformations. It’s also useful for debugging.

Is _.template safe from XSS?

_.template with <%= %> does NOT escape output. Use <%- %> for escaped interpolation. Never use _.template with untrusted template strings — the source option allows arbitrary code execution.

When should I use _.isNil vs _.isEmpty?

_.isNil checks specifically for null or undefined. _.isEmpty checks if a value has no enumerable properties — which is true for null, undefined, empty arrays, empty objects, empty strings, but also for primitives like 0 and true.

Try It Yourself

Experiment with case conversion, templating, slug generation, and random data in this interactive sandbox:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Lodash String Studio</title>
  <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
  <style>
    * { box-sizing: border-box; margin: 0; padding: 0; }
    body { font-family: system-ui, -apple-system, sans-serif; background: #0f172a; color: #e2e8f0; padding: 2rem; }
    .container { max-width: 1100px; margin: 0 auto; }
    h1 { font-size: 1.75rem; margin-bottom: 0.25rem; }
    .subtitle { color: #94a3b8; margin-bottom: 1.5rem; }
    .tabs { display: flex; gap: 0.25rem; margin-bottom: 1.5rem; border-bottom: 1px solid #334155; }
    .tab { padding: 0.5rem 1rem; cursor: pointer; font-size: 0.875rem; color: #94a3b8; background: none; border: none; border-bottom: 2px solid transparent; }
    .tab:hover { color: #e2e8f0; }
    .tab.active { color: #38bdf8; border-bottom-color: #38bdf8; }
    .panel { display: none; }
    .panel.active { display: block; }
    .card { background: #1e293b; border-radius: 0.75rem; padding: 1.5rem; border: 1px solid #334155; margin-bottom: 1rem; }
    .card h2 { font-size: 1.05rem; margin-bottom: 0.75rem; color: #38bdf8; }
    .card h3 { font-size: 0.85rem; color: #94a3b8; margin-bottom: 0.5rem; text-transform: uppercase; letter-spacing: 0.05em; }
    textarea, input, select { width: 100%; background: #0f172a; color: #e2e8f0; border: 1px solid #334155; border-radius: 0.375rem; padding: 0.625rem; font-family: monospace; font-size: 0.875rem; }
    textarea { min-height: 80px; resize: vertical; }
    .output-box { background: #0f172a; border: 1px solid #334155; border-radius: 0.375rem; padding: 0.75rem; min-height: 50px; font-family: monospace; font-size: 0.8125rem; white-space: pre-wrap; word-break: break-all; margin-top: 0.5rem; }
    .output-box.success { border-color: #22c55e; }
    .output-box.error { border-color: #ef4444; color: #fca5a5; }
    .grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
    .grid-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 1rem; }
    .btn { background: #38bdf8; color: #0f172a; border: none; padding: 0.4rem 1rem; border-radius: 0.375rem; font-weight: 600; cursor: pointer; font-size: 0.85rem; }
    .btn:hover { background: #7dd3fc; }
    .btn-outline { background: transparent; color: #38bdf8; border: 1px solid #38bdf8; }
    .btn-outline:hover { background: #38bdf8; color: #0f172a; }
    .btn-sm { padding: 0.25rem 0.5rem; font-size: 0.75rem; }
    .flex { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; }
    .stat { color: #94a3b8; font-size: 0.8rem; margin-top: 0.25rem; }
    .badge { background: #334155; padding: 0.125rem 0.375rem; border-radius: 0.25rem; font-size: 0.7rem; color: #94a3b8; }
    @media (max-width: 768px) { .grid-2, .grid-3 { grid-template-columns: 1fr; } }
  </style>
</head>
<body>
<div class="container">
  <h1>String Studio</h1>
  <p class="subtitle">Case conversion, templating, slug generation, truncation, and random data</p>

  <div class="tabs">
    <button class="tab active" onclick="switchTab('case', this)">Case Converter</button>
    <button class="tab" onclick="switchTab('template', this)">Template Engine</button>
    <button class="tab" onclick="switchTab('slug', this)">Slug Generator</button>
    <button class="tab" onclick="switchTab('random', this)">Random Data</button>
  </div>

  <div id="panel-case" class="panel active">
    <div class="grid-2">
      <div class="card">
        <h2>Input</h2>
        <textarea id="caseInput" oninput="updateCase()">hello world from Lodash</textarea>
        <div class="flex" style="margin-top:0.5rem;">
          <button class="btn btn-sm btn-outline" onclick="document.getElementById('caseInput').value='FOO BAR baz QUX'; updateCase()">UPPER mixed</button>
          <button class="btn btn-sm btn-outline" onclick="document.getElementById('caseInput').value='--snake_case--camelCase'; updateCase()">Edge case</button>
        </div>
      </div>
      <div class="card">
        <h2>Transformations</h2>
        <div id="caseResults"></div>
      </div>
    </div>
  </div>

  <div id="panel-template" class="panel">
    <div class="grid-2">
      <div class="card">
        <h2>Template</h2>
        <textarea id="templateInput" rows="5"><h1><%= title %></h1>
<p>Welcome, <%- user.name %>!</p>
<ul><% _.forEach(items, function(item) { %>
  <li><%= item %></li><% }); %></ul></textarea>
        <h3 style="margin-top:0.75rem;">Data (JSON)</h3>
        <textarea id="templateData" rows="5">{
  "title": "Hello World",
  "user": { "name": "<script>Alice</script>" },
  "items": ["Alpha", "Beta", "Gamma"]
}</textarea>
        <button class="btn" style="margin-top:0.5rem;" onclick="runTemplate()">Render</button>
      </div>
      <div class="card">
        <h2>Rendered HTML</h2>
        <div class="output-box success" id="templateOutput" style="min-height:120px;">Click "Render"</div>
        <div class="stat" id="templateStat">--</div>
      </div>
    </div>
  </div>

  <div id="panel-slug" class="panel">
    <div class="grid-2">
      <div class="card">
        <h2>Title / Text</h2>
        <textarea id="slugInput" oninput="updateSlug()">My Blog Post Title: Tips & Tricks for 2024!</textarea>
        <div class="flex" style="margin-top:0.5rem;">
          <button class="btn btn-sm btn-outline" onclick="copySlug()">Copy Slug</button>
          <label style="color:#94a3b8;font-size:0.85rem;">Max length: <input type="number" id="slugMax" value="40" style="width:60px;display:inline;" oninput="updateSlug()" /></label>
        </div>
      </div>
      <div class="card">
        <h2>Slug Variants</h2>
        <div id="slugResults"></div>
      </div>
    </div>
  </div>

  <div id="panel-random" class="panel">
    <div class="grid-2">
      <div class="card">
        <h2>Random Generator</h2>
        <div class="flex">
          <button class="btn" onclick="generateRandom()">Generate</button>
          <label style="color:#94a3b8;font-size:0.85rem;">Count: <input type="number" id="randomCount" value="5" min="1" max="20" style="width:60px;display:inline;" /></label>
        </div>
        <div class="grid-3" style="margin-top:1rem;">
          <div><h3>Integers</h3><div class="output-box" id="randomInts" style="min-height:80px;">--</div></div>
          <div><h3>Floats (0-1)</h3><div class="output-box" id="randomFloats" style="min-height:80px;">--</div></div>
          <div><h3>Range</h3><div class="output-box" id="randomRange" style="min-height:80px;">--</div></div>
        </div>
      </div>
      <div class="card">
        <h2>Helpers</h2>
        <div>
          <h3>_.clamp</h3>
          <div style="display:flex;gap:0.5rem;align-items:center;flex-wrap:wrap;margin-top:0.25rem;">
            <input type="number" id="clampVal" value="150" style="width:80px;" />
            <span style="color:#94a3b8;">to</span>
            <input type="number" id="clampMin" value="0" style="width:80px;" />
            <span style="color:#94a3b8;">-</span>
            <input type="number" id="clampMax" value="100" style="width:80px;" />
            <button class="btn btn-sm" onclick="runClamp()">Clamp</button>
            <strong id="clampResult" style="color:#38bdf8;">--</strong>
          </div>
        </div>
        <div style="margin-top:1rem;">
          <h3>_.range</h3>
          <div style="display:flex;gap:0.5rem;align-items:center;flex-wrap:wrap;margin-top:0.25rem;">
            <input type="text" id="rangeParams" value="1, 10, 2" style="width:150px;" placeholder="start, end, step" />
            <button class="btn btn-sm" onclick="runRange()">Range</button>
            <strong id="rangeResult" style="color:#38bdf8;font-size:0.8rem;">--</strong>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

<script>
function switchTab(name, btn) {
  document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
  document.querySelectorAll('.panel').forEach(p => p.classList.remove('active'));
  btn.classList.add('active');
  document.getElementById('panel-' + name).classList.add('active');
}

function updateCase() {
  const val = document.getElementById('caseInput').value;
  if (!val) { document.getElementById('caseResults').innerHTML = ''; return; }
  document.getElementById('caseResults').innerHTML = `
    <div class="stat">camelCase: <strong>${_.camelCase(val)}</strong></div>
    <div class="stat">kebabCase: <strong>${_.kebabCase(val)}</strong></div>
    <div class="stat">snakeCase: <strong>${_.snakeCase(val)}</strong></div>
    <div class="stat">startCase: <strong>${_.startCase(val)}</strong></div>
    <div class="stat">lowerCase: <strong>${_.lowerCase(val)}</strong></div>
    <div class="stat">upperCase: <strong>${_.upperCase(val)}</strong></div>
    <div class="stat">escape: <strong>${_.escape(val)}</strong></div>
    <div class="stat">unescape: <strong>${_.unescape(_.escape(val))}</strong></div>
  `;
}

function runTemplate() {
  const tmpl = document.getElementById('templateInput').value;
  const dataStr = document.getElementById('templateData').value;
  let data;
  try { data = JSON.parse(dataStr); } catch {
    document.getElementById('templateOutput').textContent = 'Invalid JSON data';
    document.getElementById('templateOutput').className = 'output-box error';
    return;
  }
  try {
    const compiled = _.template(tmpl);
    const html = compiled(data);
    document.getElementById('templateOutput').innerHTML = html;
    document.getElementById('templateOutput').className = 'output-box success';
    document.getElementById('templateStat').innerHTML = 'Rendered ' + html.length + ' chars';
  } catch (e) {
    document.getElementById('templateOutput').textContent = 'Template error: ' + e.message;
    document.getElementById('templateOutput').className = 'output-box error';
  }
}

function updateSlug() {
  const val = document.getElementById('slugInput').value;
  const max = parseInt(document.getElementById('slugMax').value) || 40;
  if (!val) { document.getElementById('slugResults').innerHTML = ''; return; }
  const slug = _.kebabCase(val);
  const truncated = _.truncate(slug, { length: max, omission: '' });
  document.getElementById('slugResults').innerHTML = `
    <div class="stat">kebabCase slug: <strong>${slug}</strong></div>
    <div class="stat">Truncated (${max}): <strong>${truncated}</strong></div>
    <div class="stat">snakeCase: <strong>${_.snakeCase(val)}</strong></div>
    <div class="stat">slug length: <strong>${slug.length}</strong> chars</div>
  `;
}

function copySlug() {
  const slug = _.kebabCase(document.getElementById('slugInput').value);
  navigator.clipboard.writeText(slug).then(() => alert('Slug copied: ' + slug));
}

function generateRandom() {
  const count = parseInt(document.getElementById('randomCount').value) || 5;
  const ints = _.times(count, () => _.random(1, 100));
  const floats = _.times(count, () => _.random(0, 1, true).toFixed(4));
  const range = _.times(count, () => _.random(10, 50));
  document.getElementById('randomInts').textContent = ints.join(', ');
  document.getElementById('randomFloats').textContent = floats.join(', ');
  document.getElementById('randomRange').textContent = range.join(', ');
}

function runClamp() {
  const val = parseFloat(document.getElementById('clampVal').value);
  const min = parseFloat(document.getElementById('clampMin').value);
  const max = parseFloat(document.getElementById('clampMax').value);
  document.getElementById('clampResult').textContent = _.clamp(val, min, max);
}

function runRange() {
  const str = document.getElementById('rangeParams').value;
  const parts = str.split(',').map(s => parseInt(s.trim()));
  if (parts.length < 1) return;
  const result = parts.length === 1 ? _.range(parts[0]) : _.range(parts[0], parts[1], parts[2] || 1);
  document.getElementById('rangeResult').textContent = '[' + result.join(', ') + ']';
}

updateCase();
updateSlug();
</script>
</body>
</html>

What’s Next

You’ve completed the full Lodash track. Here’s where to go from here:

StepTopicWhy
JavaScript FundamentalsReview core JavaScript conceptsStrengthen your foundation
Axios HTTP RequestsLearn HTTP request handling with AxiosCombine with Lodash for API data pipelines
Node.jsServer-side JavaScriptApply Lodash in backend data processing
ReactFrontend frameworkUse Lodash for state transformations
JSON DataData interchange formatEssential for API and config handling

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro — where Lodash powers everything from file signature scanning pipelines to configuration management.

What’s Next

Congratulations on completing this Lodash Utilities tutorial! Here’s where to go from here:

  • Practice daily — Consistency is more important than long study sessions
  • Build a project — Apply what you learned by building something real
  • Explore related topics — Check out other tutorials in the same category
  • Join the community — Discuss with other learners and share your progress

Remember: every expert was once a beginner. Keep coding!

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro