Lodash _.template with Statement in ES6 Strict Mode

In ECMAScript 6 (ES6) strict mode, the JavaScript with statement is prohibited and results in an immediate syntax error. By default, Lodash's _.template utility generates code wrapped within a with block to allow template strings to reference data properties directly without requiring an explicit object namespace. When operating in an ES6 strict environment, developers must configure the variable option to bypass this behavior, ensuring templates compile and execute without violating strict mode constraints.

The Default Behavior of _.template

Under normal conditions, _.template creates dynamic functions using the Function constructor. To allow developers to write templates like <%= name %> instead of <%= data.name %>, Lodash wraps the evaluation logic in a with (obj || {}) { ... } block.

This construct places the provided data object at the top of the scope chain during template evaluation, making all object properties locally accessible within the template's interpolation tags.

The Conflict with ES6 Strict Mode

ES6 modules and strict mode scripts ("use strict";) explicitly ban the with statement. The with statement obscures variable lookups at compile time, hindering modern JavaScript engine optimizations and introducing ambiguity regarding variable scoping.

If a template compiled by Lodash is evaluated in a context enforcing strict mode, or if "use strict"; is introduced directly into the generated template function, the JavaScript engine halts execution and throws a SyntaxError: Strict mode code may not include a with statement.

Resolving the Issue Using the variable Option

Lodash provides a built-in mechanism to disable the with statement: the variable option. Setting this property forces Lodash to scope the template's data directly to a designated variable name instead of relying on a with block.

You can set this on an individual template:

const compiled = _.template('Hello <%= data.name %>!', { variable: 'data' });
compiled({ name: 'World' });

Alternatively, you can apply this configuration globally across all templates:

_.templateSettings.variable = 'data';

const compiled = _.template('Hello <%= data.name %>!');
compiled({ name: 'World' });

Generated Code Comparison

When the variable option is omitted, Lodash constructs a function body structured roughly like this:

function(obj) {
  var __t, __p = '';
  with (obj || {}) {
    __p += 'Hello ' + ((__t = (name)) == null ? '' : __t) + '!';
  }
  return __p;
}

When the variable option is defined (e.g., as 'data'), the with statement is omitted entirely:

function(data) {
  var __t, __p = '';
  __p += 'Hello ' + ((__t = (data.name)) == null ? '' : __t) + '!';
  return __p;
}

Performance and Reliability Benefits

Aside from strict mode compliance, specifying an explicit data variable yields two key technical advantages:

  1. Performance: Engines like V8 deoptimize code inside with blocks because variable scopes cannot be statically analyzed. Removing with allows the JIT compiler to optimize property access.
  2. Deterministic Scoping: Without with, there is no risk of template data inadvertently shadowing global variables or built-in JavaScript keywords, reducing runtime bugs.