Why Lodash _.template Uses With and Strict Mode

This article explores why the Lodash _.template utility historically relies on JavaScript’s with statement to scope data variables within compiled templates. It examines the ergonomics behind this design choice, the technical incompatibilities and performance penalties it introduces in ECMAScript strict mode, and how configuring the variable option resolves these issues.

The Purpose of with in _.template

Lodash’s _.template compiles micro-template strings into executable JavaScript functions. By default, it wraps the internal template code inside a with (obj) statement.

The primary reason for this approach is syntax ergonomics. In a template, developers typically want to reference properties directly:

<div>Hello, <%= name %>!</div>

Without a with statement or an explicit namespace, the template engine would need to do one of two things to resolve name:

  1. Parse the template expressions via an AST (Abstract Syntax Tree) to discover every variable identifier and explicitly declare or destructure them (e.g., const { name } = obj;).
  2. Require users to prefix every variable with a data namespace, such as <%= data.name %>.

The with statement offers a lightweight, low-overhead mechanism for the engine. It adds the supplied data object to the top of the scope chain, allowing bare variable identifiers like name to resolve dynamically to obj.name at runtime without requiring static analysis during template compilation.

The Strict Mode Implications

While convenient for template authoring, the with statement introduces severe conflicts with modern JavaScript environments that enforce strict mode ("use strict";).

1. Syntax Errors in Strict Mode

ECMAScript 5 banned with statements outright in strict mode. If a project executes under strict mode—which is standard in ES modules, modern bundlers, and TypeScript environments—any function containing a with statement throws a runtime SyntaxError:

SyntaxError: Strict mode code may not include a with statement

Because Lodash creates the compiled template function using the Function constructor, the generated code runs in sloppy mode by default unless strict mode is explicitly injected. However, if the compilation environment or downstream tooling attempts to enforce strict mode on all evaluated code, the template will immediately fail.

2. Engine Optimization and Performance Costs

Even when strict mode is not explicitly enforced, the with block negatively impacts performance. JavaScript engines like V8 optimize property lookups using static lexical scoping and hidden classes.

Because with dynamically injects an arbitrary object into the scope chain, the engine cannot determine at compile time whether an identifier refers to an object property or an outer scope variable. As a result:

The Solution: Using the variable Setting

Lodash provides a built-in mechanism to eliminate the with statement entirely by defining the variable property in _.templateSettings or within the individual template options.

// Specifying an explicit namespace
const compiled = _.template('<div>Hello, <%= data.name %>!</div>', {
  variable: 'data'
});

compiled({ name: 'World' });

When the variable option is defined:

Defining an explicit data variable produces faster, modern, and strict-mode-safe template functions at the cost of requiring callers to prefix template variables with the chosen namespace.