Skip to content

Transpile ES7 features to ES5

BabelJS - Transpiling ES2016 (ES7) Features to ES5

Section titled “BabelJS - Transpiling ES2016 (ES7) Features to ES5”

ECMAScript 2016 (formerly ES7) introduced a couple of notable features to JavaScript. While modern browsers have good support for these, you might need to transpile them to ES5 if you’re targeting older environments. BabelJS, particularly with @babel/preset-env, handles these transformations.

The main features added in ES2016 are:

  • Exponentiation Operator (**)
  • Array.prototype.includes()

(Note: Async/Await, often associated with this era, was officially standardized in ES2017. We’ll cover its transpilation separately or as part of ES2017 features, but the principles are similar.)

We’ll focus on transpiling these to ES5. By default, @babel/preset-env without specific targets will transpile to ES5. For features like Array.prototype.includes(), Babel can’t just transpile syntax; it’s a new method. This requires a polyfill.

The exponentiation operator provides a shorthand for Math.pow().

let num = 2;
let powerOfThree = num ** 3; // 2 to the power of 3
console.log(`${num} raised to the power of 3 is ${powerOfThree}`); // Outputs: 2 raised to the power of 3 is 8
let squared = 5 ** 2;
console.log(`5 squared is ${squared}`); // Outputs: 5 squared is 25

To transpile this, ensure you have Babel configured (e.g., with babel.config.json using @babel/preset-env).

{
"presets": ["@babel/preset-env"]
}
npx babel exponentiation.js --out-file exponentiation_es5.js

Transpiled ES5 Code (exponentiation_es5.js)

Section titled “Transpiled ES5 Code (exponentiation_es5.js)”
"use strict";
var num = 2;
var powerOfThree = Math.pow(num, 3); // 2 to the power of 3
console.log("".concat(num, " raised to the power of 3 is ").concat(powerOfThree)); // Outputs: 2 raised to the power of 3 is 8
var squared = Math.pow(5, 2);
console.log("5 squared is ".concat(squared)); // Outputs: 5 squared is 25

Babel correctly converts the ** operator to its Math.pow() equivalent, which is available in all ES5 environments.

Array.prototype.includes() is a convenient method to check if an array contains a certain element, returning true or false. Unlike the exponentiation operator, this is a new method on Array.prototype. Babel cannot simply transpile syntax for this; it requires a polyfill to provide the includes method functionality in environments where it’s missing.

let numbers = [1, 2, 3, 4, 5];
console.log(numbers.includes(3)); // true
console.log(numbers.includes(6)); // false
let pets = ['cat', 'dog', 'bat'];
console.log(pets.includes('cat')); // true
console.log(pets.includes('hamster')); // false

If you transpile this code with Babel using only @babel/preset-env without polyfill configuration, the JavaScript syntax itself (the method call) will remain largely unchanged because it’s valid syntax. However, it won’t work in an old browser that doesn’t have Array.prototype.includes.

Transpiled ES5 Code (Syntactically, without polyfill applied yet)

Section titled “Transpiled ES5 Code (Syntactically, without polyfill applied yet)”
"use strict";
var numbers = [1, 2, 3, 4, 5];
console.log(numbers.includes(3)); // true in modern env, error or undefined in old env
console.log(numbers.includes(6)); // false in modern env, error or undefined in old env
var pets = ['cat', 'dog', 'bat'];
console.log(pets.includes('cat')); // true
console.log(pets.includes('hamster')); // false

To make Array.prototype.includes() work in older environments, you need to provide a polyfill. The recommended way with modern Babel is to use core-js. You can configure @babel/preset-env to automatically include polyfills from core-js based on usage and your target environments.

  1. Install core-js:
npm install --save core-js
  1. Update babel.config.json:
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage", // or "entry"
"corejs": 3 // Specify core-js version
}
]
]
}

With "useBuiltIns": "usage", Babel will analyze your code and add specific import 'core-js/...' statements only for the features you use that are not supported by your target environments. If no targets are specified, it assumes older environments.

When you transpile array_includes.js now, Babel will prepend imports like:

// Example of what Babel might add at the top of array_includes_es5.js:
// import "core-js/modules/es.array.includes.js";
// (if using a bundler, otherwise it might be different)
"use strict";
// ... rest of your transpiled code ...
var numbers = [1, 2, 3, 4, 5];
console.log(numbers.includes(3));
// ...

This imported core-js module provides the Array.prototype.includes implementation if it’s missing. Now, the code will work correctly even in older browsers that support ES5 but lack includes.

Alternatively, using "useBuiltIns": "entry" requires you to add import "core-js"; and import "regenerator-runtime/runtime"; (if using async/generators) at the entry point of your application. Babel will then replace these with specific imports based on your targets.

To test polyfilled code in a browser, you’d typically bundle your JavaScript (e.g., using Webpack or Rollup), which resolves the import statements for core-js. Your HTML would then include this bundle.

test.html (assuming bundled output bundle.js):

<!DOCTYPE html>
<html>
<head>
<title>BabelJS ES2016 Test</title>
</head>
<body>
<p>Check the console for output.</p>
<script src="bundle.js"></script>
<!-- bundle.js would contain transpiled code + core-js polyfills -->
</body>
</html>

When you open this HTML in an older browser, the console should correctly show:

true
false
true
false

This demonstrates the power of Babel not just for syntax transformation but, in conjunction with polyfill libraries like core-js, for providing missing functionalities in older JavaScript environments.

For more details on polyfilling, refer to the dedicated chapter on Polyfills and the official Babel and core-js documentation.