JavaScript ES6 vs ES5: Key Features Comparison

 



ES6 vs ES5: Key Features Comparison

ES6 was a monumental update that fundamentally transformed JavaScript from a simple scripting language into a robust language suitable for large-scale application development. It added syntactic sugar, new powerful features, and solved many common pain points of ES5.

1. Variable Declarations: let and const

ES5: Only var, which is function-scoped and prone to issues like accidental re-declaration and hoisting.


var x = 10;
var x = 20; // No error, just overwrites
    

ES6: Introduced block-scoped let and const. let for variables that can be reassigned. const for variables that should not be reassigned.


let name = "Alice";
name = "Bob"; // OK

const pi = 3.14159;
// pi = 3; // Error: Assignment to constant variable.

if (true) {
  let blockScoped = "inside"; // Only exists in this block
}
// console.log(blockScoped); // Error: not defined
    

2. Arrow Functions =>

ES5: Verbose function syntax, especially for callbacks. The this keyword is dynamically scoped, leading to common workarounds.


var add = function(a, b) {
  return a + b;
};

arr.map(function(x) { return x * 2; });
    

ES6: Concise syntax and lexically scoped this (it inherits this from the surrounding code). Perfect for short callbacks and methods.


const add = (a, b) => a + b;

arr.map(x => x * 2);

// Lexical 'this' - no more 'var self = this'
setTimeout(() => {
  console.log(this.someValue); // 'this' is from the outer scope
}, 100);
    

3. Template Literals (Template Strings)

ES5: Cumbersome string concatenation.


var name = "Sarah";
var greeting = "Hello, " + name + "!\nWelcome to " + company + ".";
    

ES6: Use backticks ` and ${} for interpolation and multi-line strings.


const name = "Sarah";
const greeting = `Hello, ${name}!
Welcome to ${company}.`;
    

4. Destructuring Assignment

ES5: Extracting data from objects/arrays required repetitive code.


var user = {name: 'Alex', age: 30};
var userName = user.name;
var userAge = user.age;

var arr = [1, 2, 3];
var first = arr[0];
    

ES6: Extract data from arrays or objects into distinct variables using a syntax that mirrors their construction.


// Object Destructuring
const user = {name: 'Alex', age: 30};
const {name, age} = user; // Creates variables 'name' and 'age'

// Array Destructuring
const arr = [1, 2, 3];
const [first, second] = arr; // first = 1, second = 2

// Function Parameter Destructuring
function greet({name, age}) {
  return `Hello ${name}, you are ${age}.`;
}
    

5. Default Parameters

ES5: Had to use logical OR (||) tricks to set defaults.


function greet(name) {
  name = name || 'Guest';
}
    

ES6: Specify default values directly in the function signature.


function greet(name = 'Guest', age = 18) {
  return `Hello ${name}`;
}
greet(); // "Hello Guest"
    

6. Enhanced Object Literals

ES5: Objects were more verbose to define.


var obj = {
  prop: propValue,
  method: function() { ... }
};
    

ES6: Shorthand for defining properties and methods.


const propValue = 10;
const obj = {
  propValue, // Shorthand property (same as propValue: propValue)
  method() { // Shorthand method (no 'function' keyword)
    // ...
  },
  // Computed property names
  [`prop_${42}`]: 'Life' // Property name is computed at runtime
};
    

7. Promises

ES5: Async operations used callbacks, leading to "callback hell" or deeply nested callbacks.


asyncFunction(arg, function(result) {
  anotherAsyncFunction(result, function(newResult) {
    // Callback hell
  });
});
    

ES6: Introduced the Promise object for managing asynchronous operations. It provides a cleaner, chainable syntax for handling success and error cases.


asyncFunction(arg)
  .then(result => anotherAsyncFunction(result))
  .then(newResult => {
    // Handle new result
  })
  .catch(error => {
    // Handle any error in the chain
  });
    

8. Classes

ES5: Used constructor functions and prototype inheritance, which was unfamiliar to developers from class-based languages.


function Person(name) {
  this.name = name;
}
Person.prototype.sayName = function() {
  console.log(this.name);
};
    

ES6: Provides a much clearer and more familiar syntax for creating objects and dealing with inheritance (syntactic sugar over prototype-based inheritance).


class Person {
  constructor(name) {
    this.name = name;
  }
  sayName() {
    console.log(this.name);
  }
}

class Developer extends Person { // 'extends' for inheritance
  constructor(name, language) {
    super(name); // Call the parent constructor
    this.language = language;
  }
}
    

9. Modules: import / export

ES5: No native module system. Relied on libraries like RequireJS or CommonJS (Node.js).


// CommonJS (Node.js)
var lib = require('./lib');
module.exports = function() { ... };
    

ES6: Native support for modular code.


// lib.js - Exports
export const apiKey = '123abc';
export function sum(a, b) { return a + b; }
export default class User { ... } // Default export

// app.js - Imports
import User, { apiKey, sum } from './lib'; // Import default + named exports
    

Other Notable ES6 Features:

  • Rest/Spread Operator (...): function(...args) collects arguments into an array. [...arr] spreads an array into elements.
  • Iterators & for...of loop: A unified way to iterate over data structures (arrays, maps, strings).
  • New Built-in Methods: Helpers like Array.prototype.find(), String.prototype.includes(), Object.assign().
  • Map and Set Collections: Data structures for key/value pairs and unique values, respectively.
  • Symbols: A new primitive type for creating unique property keys.

Conclusion

ES6 made JavaScript code more expressive, concise, and readable. It provided modern language constructs (classes, modules) and solved long-standing problems (scoping with let/const, this binding with arrow functions), paving the way for the modern JavaScript ecosystem.

Comments