Variable Scoping and Temporal Dead Zone
JavaScript's variable declaration mechanisms underwent significant refinement in ES6. The legacy var keyword exhibits function-scoping and hoisting behavior, where declarations migrate to the top of their containing scope during compilation phase.
console.log(counter); // undefined
var counter = 5;
Conceptually, the runtime interprets this as:
var counter;
console.log(counter); // undefined
counter = 5;
In contrast, let and const establish block-level scoping and introduce the temporal dead zone—a period between scope entry and declaration where accessing the variable triggers a ReferenceError.
console.log(threshold); // ReferenceError: Cannot access 'threshold' before initialization
let threshold = 100;
Additionally, const mandates assignment during declaration and prevents rebinding, though object mutations remain permissible.
Inheritance Mechanisms
Constructor Functions
Prier to ES6, inheritance relied on constructor functions and prototype manipulation:
function Vehicle(type) {
this.type = type;
}
Vehicle.prototype.getType = function() {
return this.type;
};
function Car(type, model) {
Vehicle.call(this, type);
this.model = model;
}
Car.prototype = Object.create(Vehicle.prototype);
Car.prototype.constructor = Car;
const sedan = new Car('car', 'sedan');
sedan.getType(); // 'car'
This approach requires manual prototype chain setup and loses the constructor reference without explicit correction.
Class Syntax
ES6 classes provide cleaner abstraction over prototypal inheritance:
class Vehicle {
constructor(type) {
this.type = type;
}
getType() {
return this.type;
}
}
class Car extends Vehicle {
constructor(type, model) {
super(type);
this.model = model;
}
}
const suv = new Car('car', 'suv');
console.log(suv instanceof Vehicle); // true
While syntactically distinct, classes internally utilize the same prototype-based delegation model.
Module Architecture
Immediate Invocation Pattern
Pre-ES6 modularization relied on function scoping to encapsulate implementation details:
const utils = (function(global) {
const privateVar = 'hidden';
function privateMethod() {
return privateVar;
}
return {
expose: privateMethod
};
})(window);
CommonJS
Server-side environments historically adopted CommonJS:
// math.js
module.exports = {
calculate: (x, y) => x + y
};
// app.js
const math = require('./math');
console.log(math.calculate(2, 3)); // 5
ES6 Modules
The standardized module system enables static analysis and tree-shaking:
// config.js
export const API_URL = 'https://api.example.com';
// main.js
import { API_URL } from './config.js';
console.log(API_URL);
Proxy for Interception
The Proxy API enables meta-programming through operation interception:
const validator = {
set(target, prop, value) {
if (prop === 'age' && typeof value !== 'number') {
throw new TypeError('Age must be numeric');
}
target[prop] = value;
return true;
}
};
const person = new Proxy({}, validator);
person.age = 25; // Valid
// person.age = 'twenty'; // Throws TypeError
Array Transformation Methods
Mapping
Transform elements through functional projection:
const measurements = [10, 20, 30];
const tripled = measurements.map(x => x * 3);
// [30, 60, 90]
Filtering
Select subset based on predicates:
const scores = [85, 92, 78, 95];
const passing = scores.filter(s => s >= 80);
// [85, 92, 95]
Reduction
Accumulate values into composite results:
const transactions = [10, -5, 20, -3];
const balance = transactions.reduce((acc, curr) => acc + curr, 0);
// 22
Dictionary Implementations
Plain Objects
Standard objects restrict keys too strings and symbols, lacking guaranteed iteration order and requiring prototype pollution safeguards.
Map Collections
Map structures accept arbitrary key types and preserve insertion sequence:
const userCache = new Map();
userCache.set(101, { name: 'Alice' });
userCache.set(102, { name: 'Bob' });
for (const [id, data] of userCache) {
console.log(id, data);
}
WeakMap
WeakMap maintains weak references to object keys, enabling private data attachment without preventing garbage collection:
const privateData = new WeakMap();
class SecureBox {
constructor(secret) {
privateData.set(this, { secret });
}
reveal() {
return privateData.get(this).secret;
}
}