ES6-like template strings in 10 lines of ES5

Zack Argyle
2 min readNov 2, 2015

--

Inserting values into strings is one of the most common things we do in front-end development. There are a lot of different templating engines that engineers use: underscore, mustache, handlebars, nunjucks, etc. One of the nice new features of Ecmascript 6 is template strings, allowing native string templating without the inclusion of third party libraries. Check out this 10-line function that provides ES6-like templating, without the overhead of a transpiler or external libraries. http://codepen.io/zackargyle/pen/qOKJBj

Writing a basic templating function is fairly straight-forward with String.prototype.replace. You can use a regular expression to capture anything defined within your template symbols. The simple expression I am using for this function simply matches the ES6 ${…} syntax and captures the content.

/\${(.*?)}/g

We can’t quite get the exact functionality of ES6 template strings, including things like tagged templates or multiline strings, but we can have the templating support. Here’s the function.

String.prototype.eval = function(data) {  
return this.replace(/\${(.*?)}/g, function(_, code) {
var scoped = code.replace(/(["'\.\w\$]+)/g, function(match) {
return /["']/.test(match[0]) ? match : 'scope.' + match;
});
try {
return new Function('scope', 'return '+ scoped)(data);
} catch (e) { return ''; }
});
}

This function does a couple of clever things, which by no means are the most fast, secure or best practice. First is to prefix anything that looks like a variable inside the template content with “scope.” This allows us to not require a prefix in the template string. So instead of ${data.name} we can just write ${name}. Then we create a function and call it with the data argument. The anonymous function returns the “scoped” content.

Essentially, the function lets us do things like this.

var data = {
name1: 'Silento',
name2: 'Miley',
nested: { greeting: 'Dude', useName1: true },
verb: function() {
return this.nested.useName1 ? 'nae nae' : 'twerk';
}
};
'Hello, ${nested["greeting"]}!'.eval(data);
// returns 'Hello, Dude!'
'${nested.useName1 ? name1 : name2}'.eval(data);
// returns 'Silento'
'${name1} likes to ${verb()}'.eval(data);
// returns 'Silento likes to nae nae'

Check out the demo here. http://codepen.io/zackargyle/pen/qOKJBj

ES6 is awesome, and I would highly suggest using something like Babel rather than hacking something like this together if possible. Though there are situations where you need to be as lightweight as possible, and cannot use libraries. Simple hacks like this can allow you to reuse templates across projects regardless of requirements.

--

--