January 15, 2024
Ten advanced Javascript knowledge and usage
Hi, today I’ve compiled ten advanced concepts in JavaScript for you, hoping it will be helpful.

By Jack Smith
2 min read
- Higher-Order Functions
Higher-order functions refer to functions that take one or more functions as parameters and/or return a function. This technique can be used to compose functions and achieve function reuse.
// Higher-order function example: Sum all elements in an array
function add(...args) {
return args.reduce((a, b) => a + b, 0);
}
function addArrayElements(arr, fn) {
return fn(...arr);
}
const arr = [1, 2, 3, 4, 5];
const sum = addArrayElements(arr, add);
console.log(sum); // 15// Higher-order function example: Sum all elements in an array
function add(...args) {
return args.reduce((a, b) => a + b, 0);
}
function addArrayElements(arr, fn) {
return fn(...arr);
}
const arr = [1, 2, 3, 4, 5];
const sum = addArrayElements(arr, add);
console.log(sum); // 15- Pure Functions
Pure functions are functions with no side effects (do not change external state) and whose output is solely determined by the input. Pure functions make unit testing and debugging easier and align better with functional programming concepts.
// Pure function example: Convert all elements in an array to strings
function arrToString(arr) {
return arr.map(String);
}
const arr = [1, 2, 3, 4, 5];
const strArr = arrToString(arr);
console.log(strArr); // ["1", "2", "3", "4", "5"]// Pure function example: Convert all elements in an array to strings
function arrToString(arr) {
return arr.map(String);
}
const arr = [1, 2, 3, 4, 5];
const strArr = arrToString(arr);
console.log(strArr); // ["1", "2", "3", "4", "5"]- Closures
Closures refer to a function's ability to access variables outside of its defined scope. This technique is used to "encapsulate" variables, preventing the misuse of global variables.
// Closure example: Implementing a counter using closures
function makeCounter() {
let count = 0;
return function() {
count++;
console.log(count);
};
}
const counter = makeCounter();
counter(); // 1
counter(); // 2
counter(); // 3// Closure example: Implementing a counter using closures
function makeCounter() {
let count = 0;
return function() {
count++;
console.log(count);
};
}
const counter = makeCounter();
counter(); // 1
counter(); // 2
counter(); // 3- Currying
Currying is the technique of transforming a function that takes multiple arguments into a sequence of functions that each take a single argument. This technique enhances the versatility of functions.
// Currying example: Transform a function that takes multiple arguments into a sequence of functions
function add(a) {
return function(b) {
return a + b;
};
}
const add5 = add(5);
console.log(add5(10)); // 15
console.log(add5(20)); // 25// Currying example: Transform a function that takes multiple arguments into a sequence of functions
function add(a) {
return function(b) {
return a + b;
};
}
const add5 = add(5);
console.log(add5(10)); // 15
console.log(add5(20)); // 25- Function Composition
Function composition involves combining multiple functions into one function. This technique allows passing the output of one function as the input to the next, promoting function reuse.
// Function composition example: Combine multiple functions into one function
function add(a, b) {
return a + b;
}
function multiply(a, b) {
return a * b;
}
function compose(...fns) {
return function(x, y) {
return fns.reduce((acc, fn) => fn(acc, y), x);
};
}
const addAndMultiply = compose(add, multiply);
console.log(addAndMultiply(2, 3)); // 15// Function composition example: Combine multiple functions into one function
function add(a, b) {
return a + b;
}
function multiply(a, b) {
return a * b;
}
function compose(...fns) {
return function(x, y) {
return fns.reduce((acc, fn) => fn(acc, y), x);
};
}
const addAndMultiply = compose(add, multiply);
console.log(addAndMultiply(2, 3)); // 15- Function Memoization
Function memoization involves using caching to store function results, avoiding redundant calculations and enhancing function performance.
// Function memoization example: Use caching to store function results
function memoize(fn) {
const cache = {};
return function(...args) {
const key = JSON.stringify(args);
if (cache[key]) {
return cache[key];
}
const result = fn(...args);
cache[key] = result;
return result;
};
}
function add(a, b) {
console.log("Calculating sum...");
return a + b;
}
const memoizedAdd = memoize(add);
console.log(memoizedAdd(2, 3)); // Calculating sum... 5
console.log(memoizedAdd(2, 3)); // 5 (from cache)// Function memoization example: Use caching to store function results
function memoize(fn) {
const cache = {};
return function(...args) {
const key = JSON.stringify(args);
if (cache[key]) {
return cache[key];
}
const result = fn(...args);
cache[key] = result;
return result;
};
}
function add(a, b) {
console.log("Calculating sum...");
return a + b;
}
const memoizedAdd = memoize(add);
console.log(memoizedAdd(2, 3)); // Calculating sum... 5
console.log(memoizedAdd(2, 3)); // 5 (from cache)- Classes and Inheritance
Classes and inheritance involve organizing code using object-oriented programming concepts, making code more modular and maintainable.
// Classes and inheritance example: Implementing Animal and Cat classes
class Animal {
constructor(name, age) {
this.name = name;
this.age = age;
}
speak() {
console.log("I am an animal.");
}
}
class Cat extends Animal {
constructor(name, age, color) {
super(name, age);
this.color = color;
}
speak() {
console.log("Meow!");
}
}
const cat = new Cat("Fluffy", 2, "black");// Classes and inheritance example: Implementing Animal and Cat classes
class Animal {
constructor(name, age) {
this.name = name;
this.age = age;
}
speak() {
console.log("I am an animal.");
}
}
class Cat extends Animal {
constructor(name, age, color) {
super(name, age);
this.color = color;
}
speak() {
console.log("Meow!");
}
}
const cat = new Cat("Fluffy", 2, "black");- Generators
Generators are special functions that can pause and resume execution, used to create iterators.
function* generate() {
yield 1;
yield 2;
yield 3;
}
const iterator = generate();
console.log(iterator.next()); // Output: { value: 1, done: false }
console.log(iterator.next()); // Output: { value: 2, done: false }
console.log(iterator.next()); // Output: { value: 3, done: false }
console.log(iterator.next()); // Output: { value: undefined, done: true }function* generate() {
yield 1;
yield 2;
yield 3;
}
const iterator = generate();
console.log(iterator.next()); // Output: { value: 1, done: false }
console.log(iterator.next()); // Output: { value: 2, done: false }
console.log(iterator.next()); // Output: { value: 3, done: false }
console.log(iterator.next()); // Output: { value: undefined, done: true }- Proxy
Proxy is an object proxy mechanism that intercepts object access, assignment, deletion, etc. It can be used for data validation, caching, and other functionalities.
const user = {
name: 'John',
age: 30,
};
const proxy = new Proxy(user, {
get(target, key) {
console.log(`Getting ${key} value.`);
return target[key];
},
set(target, key, value) {
console.log(`Setting ${key} value to ${value}.`);
target[key] = value;
},
});
console.log(proxy.name); // Outputs: "Getting name value." and "John"
proxy.age = 40; // Outputs: "Setting age value to 40."const user = {
name: 'John',
age: 30,
};
const proxy = new Proxy(user, {
get(target, key) {
console.log(`Getting ${key} value.`);
return target[key];
},
set(target, key, value) {
console.log(`Setting ${key} value to ${value}.`);
target[key] = value;
},
});
console.log(proxy.name); // Outputs: "Getting name value." and "John"
proxy.age = 40; // Outputs: "Setting age value to 40."- Reflect
Reflect is an object reflection mechanism that provides a set of methods for object manipulation. It can replace some functionalities previously only achievable through Object methods.
const user = {
name: 'John',
age: 30,
};
console.log(Reflect.has(user, 'name')); // Outputs: true
console.log(Reflect.get(user, 'name')); // Outputs: "John"
console.log(Reflect.set(user, 'age', 40)); // Outputs: true
console.log(user.age); // Outputs: 40const user = {
name: 'John',
age: 30,
};
console.log(Reflect.has(user, 'name')); // Outputs: true
console.log(Reflect.get(user, 'name')); // Outputs: "John"
console.log(Reflect.set(user, 'age', 40)); // Outputs: true
console.log(user.age); // Outputs: 40