Functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids changing state and mutable data. In JavaScript, functions are first - class citizens, which makes it well - suited for functional programming.
A pure function is a function that, given the same input, always returns the same output and has no side - effects.
// Impure function
let counter = 0;
function impureAdd() {
return ++counter;
}
// Pure function
function pureAdd(a, b) {
return a + b;
}
console.log(pureAdd(3, 5)); // Output: 8
Higher - order functions are functions that can take other functions as arguments or return functions as results.
function multiplyBy(factor) {
return function (number) {
return number * factor;
};
}
const double = multiplyBy(2);
console.log(double(5)); // Output: 10
JavaScript arrays have several built - in higher - order functions like map
, filter
, and reduce
.
const numbers = [1, 2, 3, 4];
// Map
const squaredNumbers = numbers.map(num => num * num);
console.log(squaredNumbers); // Output: [1, 4, 9, 16]
// Filter
const evenNumbers = numbers.filter(num => num % 2 === 0);
console.log(evenNumbers); // Output: [2, 4]
// Reduce
const sum = numbers.reduce((acc, num) => acc + num, 0);
console.log(sum); // Output: 10
Asynchronous programming in JavaScript allows code to run in the background without blocking the execution of other code. This is crucial for tasks like making API calls, reading files, or handling user events.
Callbacks are the oldest way to handle asynchronous operations in JavaScript.
function fetchData(callback) {
setTimeout(() => {
const data = { message: 'Hello, World!' };
callback(data);
}, 1000);
}
fetchData((result) => {
console.log(result.message);
});
Promises provide a more structured way to handle asynchronous operations.
function fetchDataPromise() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const data = { message: 'Hello from Promise!' };
resolve(data);
}, 1000);
});
}
fetchDataPromise()
.then(result => {
console.log(result.message);
})
.catch(error => {
console.error(error);
});
Async/await is a syntactic sugar built on top of Promises that makes asynchronous code look more like synchronous code.
async function getData() {
try {
const data = await fetchDataPromise();
console.log(data.message);
} catch (error) {
console.error(error);
}
}
getData();
JavaScript has support for object - oriented programming (OOP) with the addition of classes and inheritance features, which help in organizing code and creating reusable components.
ES6 introduced the class
syntax to simplify object - oriented programming in JavaScript.
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound.`);
}
}
class Dog extends Animal {
speak() {
console.log(`${this.name} barks.`);
}
}
const myDog = new Dog('Buddy');
myDog.speak(); // Output: Buddy barks.
JavaScript uses prototypal inheritance, where objects can inherit properties and methods from other objects.
const person = {
greet: function () {
console.log(`Hello, my name is ${this.name}`);
}
};
const john = Object.create(person);
john.name = 'John';
john.greet(); // Output: Hello, my name is John
Metaprogramming in JavaScript allows code to manipulate other code or itself at runtime. This includes using features like proxies and reflect.
Proxies are used to intercept and customize fundamental operations on an object.
const target = {
name: 'Alice',
age: 30
};
const handler = {
get: function (target, property) {
console.log(`Getting property ${property}`);
return target[property];
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.name); // Output: Getting property name, Alice
The Reflect
object provides a set of built - in methods for performing operations that are typically used in metaprogramming.
const obj = { x: 1, y: 2 };
Reflect.set(obj, 'z', 3);
console.log(obj.z); // Output: 3
Proper error handling is essential for building robust applications. Advanced error handling techniques in JavaScript can help in debugging and gracefully handling errors.
function divide(a, b) {
if (b === 0) {
throw new Error('Division by zero is not allowed');
}
return a / b;
}
try {
const result = divide(10, 0);
console.log(result);
} catch (error) {
console.error(error.message);
}
Performance optimization in JavaScript focuses on reducing memory usage, minimizing execution time, and improving the overall responsiveness of the application.
Debouncing is a technique used to limit the rate at which a function can fire.
function debounce(func, delay) {
let timer;
return function () {
const context = this;
const args = arguments;
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(context, args);
}, delay);
};
}
function searchFunction() {
console.log('Searching...');
}
const debouncedSearch = debounce(searchFunction, 300);
window.addEventListener('input', debouncedSearch);
Advanced JavaScript techniques offer a wide range of benefits for experienced developers. Functional programming allows for more modular and predictable code, asynchronous programming enables efficient handling of time - consuming tasks, object - oriented programming enhances code organization, metaprogramming provides flexibility, and advanced error handling and performance optimization contribute to the reliability and efficiency of applications. By mastering these techniques, developers can write high - quality, maintainable, and performant JavaScript code.