Advanced JavaScript
ES6 vs JavaScript

Key Differences Between Old JavaScript and ES6

ES6 (ECMAScript 2015) introduced a wide array of new features that significantly modernized JavaScript. These features improved syntax, readability, modularity, and introduced new capabilities like arrow functions, classes, and promises. Below is a summary of the most important ES6 features, along with examples and how they differ from "old" (pre-ES6) JavaScript.

1. let and const

  • Before ES6: Variables were declared using var, which is function-scoped and has hoisting issues.
  • ES6: Introduced let and const for block-scoped variables.
    • let: Mutable variable with block scope.
    • const: Immutable variable (its reference cannot be reassigned).

Example:

// Pre-ES6: var is function-scoped
var a = 10;
if (true) {
  var a = 20;
  console.log(a); // 20 (scope leaks outside the block)
}
console.log(a); // 20
 
// ES6: let is block-scoped
let b = 10;
if (true) {
  let b = 20;
  console.log(b); // 20 (b is block-scoped)
}
console.log(b); // 10 (no scope leak)

2. Arrow Functions (=>)

  • Before ES6: Functions were defined using the function keyword.
  • ES6: Introduced arrow functions with a shorter syntax and lexically bound this.

Example:

// Pre-ES6: Function expression
var add = function(a, b) {
  return a + b;
};
 
// ES6: Arrow function
const add = (a, b) => a + b;
 
// Lexical `this` in arrow functions
const obj = {
  name: "Alice",
  sayName: function() {
    setTimeout(function() {
      console.log(this.name); // Undefined, `this` is not bound
    }, 1000);
  }
};
 
// Using arrow function binds `this` lexically
const obj2 = {
  name: "Bob",
  sayName: function() {
    setTimeout(() => {
      console.log(this.name); // Bob, because arrow functions inherit `this`
    }, 1000);
  }
};

3. Template Literals (` `)

  • Before ES6: String concatenation was done using +.
  • ES6: Introduced template literals for easier string interpolation, multiline strings, and embedded expressions.

Example:

// Pre-ES6: String concatenation
var name = "Alice";
var greeting = "Hello, " + name + "!";
 
// ES6: Template literals
const name = "Alice";
const greeting = `Hello, ${name}!`;
 
// Multiline string
const longString = `
  This is a
  multiline string.
`;

4. Destructuring Assignment

  • Before ES6: Manually extracting properties from objects and arrays.
  • ES6: Destructuring simplifies extracting values from arrays and objects.

Example:

// Pre-ES6: Manual extraction
var person = { name: "Alice", age: 25 };
var name = person.name;
var age = person.age;
 
// ES6: Destructuring
const { name, age } = person;
 
// Array destructuring
const arr = [1, 2, 3];
const [first, second] = arr;

5. Default Parameters

  • Before ES6: Default values were set manually using conditionals.
  • ES6: Allows default values for function parameters directly in the function signature.

Example:

// Pre-ES6: Default parameters with conditionals
function greet(name) {
  var name = name || "Guest";
  console.log("Hello, " + name);
}
 
// ES6: Default parameters
const greet = (name = "Guest") => console.log(`Hello, ${name}`);

6. Rest and Spread Operators (...)

  • Before ES6: Handling variable numbers of arguments or copying arrays required manual loops or apply.
  • ES6: Introduced the rest (...args) and spread (...array) operators.
    • Rest: Gathers remaining function arguments into an array.
    • Spread: Spreads an array or object into individual elements.

Example:

// Rest operator (collect arguments)
function sum(...numbers) {
  return numbers.reduce((acc, val) => acc + val, 0);
}
 
// Spread operator (split array)
const arr = [1, 2, 3];
const newArr = [...arr, 4, 5]; // [1, 2, 3, 4, 5]

7. Classes

  • Before ES6: Inheritance and object creation were handled through prototype chains and constructor functions.
  • ES6: Introduced class syntax for creating object-oriented structures more cleanly.
    • class: A new way to declare classes.
    • extends: Allows inheritance.
    • super(): Calls the parent class constructor.

Example:

// Pre-ES6: Constructor functions
function Animal(name) {
  this.name = name;
}
Animal.prototype.speak = function() {
  console.log(`${this.name} makes a sound.`);
};
 
// ES6: Class syntax
class Animal {
  constructor(name) {
    this.name = name;
  }
 
  speak() {
    console.log(`${this.name} makes a sound.`);
  }
}
 
// Inheritance
class Dog extends Animal {
  speak() {
    console.log(`${this.name} barks.`);
  }
}

8. Modules (import/export)

  • Before ES6: JavaScript did not have native module support. Modules were implemented via third-party libraries like CommonJS (require/module.exports).
  • ES6: Introduced native module syntax with import and export.

Example:

// In myModule.js
export const greet = () => console.log("Hello!");
 
// In main.js
import { greet } from './myModule.js';
greet(); // Hello!

9. Promises

  • Before ES6: Asynchronous code was often written using callbacks, which led to "callback hell."
  • ES6: Introduced Promises, which simplify asynchronous operations and chaining.

Example:

// Pre-ES6: Callback-based async code
setTimeout(function() {
  console.log("Done!");
}, 1000);
 
// ES6: Promise-based async code
const wait = new Promise((resolve, reject) => {
  setTimeout(() => resolve("Done!"), 1000);
});
 
wait.then((message) => console.log(message)); // Done!

10. Map and Set Data Structures

  • Before ES6: JavaScript had limited built-in data structures, mainly objects and arrays.
  • ES6: Introduced Map (key-value pairs) and Set (unique values) as native data structures.

Example:

// Set example
const set = new Set([1, 2, 3, 3]);
console.log(set); // Set { 1, 2, 3 }
 
// Map example
const map = new Map();
map.set('key1', 'value1');
console.log(map.get('key1')); // value1

11. Enhanced Object Literals

  • Before ES6: Object literals had verbose syntax.
  • ES6: Enhanced object literals with shorthand properties and methods.

Example:

const name = "Alice";
const age = 25;
 
// Pre-ES6: Verbose object properties
var person = {
  name: name,
  age: age,
  greet: function() {
    return "Hello!";
  }
};
 
// ES6: Shorthand properties and methods
const person = {
  name,
  age,
  greet() {
    return "Hello!";
  }
};

12. for...of Loop

  • Before ES6: Iterating over arrays required for loops or forEach.
  • ES6: Introduced for...of for easier iteration over arrays and iterable objects.

Example:

const arr = [10, 20, 30];
 
// Pre-ES6: forEach loop
arr.forEach(function(value) {
  console.log(value);
});
 
// ES6: for...of loop
for (const value of arr) {
  console.log(value);
 
 
}

Key Differences Between Old JavaScript and ES6:

  • Scope Handling: var vs. block-scoped let and const.
  • Functions: ES6 arrow functions offer shorter syntax and lexically bound this.
  • String Handling: Template literals simplify string interpolation and multiline strings.
  • Modularity: ES6 introduced native import/export, while older JavaScript relied on third-party libraries.
  • Asynchronous Programming: Promises simplify handling asynchronous code compared to callback hell.
  • OOP Syntax: class and extends offer a more intuitive object-oriented syntax over prototype-based inheritance.