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:
- Performance: Engines like V8 deoptimize code inside
withblocks because variable scopes cannot be statically analyzed. Removingwithallows the JIT compiler to optimize property access. - Deterministic Scoping: Without
with, there is no risk of template data inadvertently shadowing global variables or built-in JavaScript keywords, reducing runtime bugs.