5 Advanced JavaScript Tricks You Might Not Know — PART 2

MentorAide
4 min readAug 6, 2024

--

6. Destructuring with Aliasing

Destructuring allows you to unpack values from arrays or properties from objects into distinct variables. With aliasing, you can rename the variables during this process, which is especially useful when dealing with data from external sources like APIs.

Use Case: Fetching data from an API and giving more meaningful names to the properties for better code readability and maintainability.

const apiResponse = { first_name: 'John', user_age: 30, address: { city: 'New York', zip: '10001' } };
const { first_name: firstName, user_age: age, address: { city: hometown, zip: postalCode } } = apiResponse;
console.log(firstName); // John
console.log(age); // 30
console.log(hometown); // New York
console.log(postalCode); // 10001

Why Use It: It helps make variable names more self-explanatory and intuitive, improving code readability and maintenance. Aliasing can also prevent name clashes and enhance code clarity when dealing with complex data structures.

7. Currying

Currying transforms a function that takes multiple arguments into a series of functions that each take a single argument. This technique is particularly useful in functional programming for creating more flexible and reusable functions.

Use Case: Creating reusable functions for applying discounts.

const applyDiscount = (discount) => (price) => price - (price * discount / 100);
const tenPercentOff = applyDiscount(10);
const twentyPercentOff = applyDiscount(20);
console.log(tenPercentOff(100)); // 90
console.log(twentyPercentOff(100)); // 80
const applyTax = (taxRate) => (price) => price + (price * taxRate / 100);
const applyTenPercentTax = applyTax(10);
console.log(applyTenPercentTax(100)); // 110
console.log(applyTenPercentTax(twentyPercentOff(100))); // 88

Why Use It: Currying allows you to preset arguments in functions, leading to more modular and composable code. This can simplify the creation of highly reusable utility functions.

8. Debouncing and Throttling

These techniques control how often a function is executed, optimizing event handlers to prevent excessive function calls that can degrade performance.

Debouncing ensures that a function is not called again until a certain amount of time has passed since the last call.

Use Case: Optimizing a search input field to reduce the number of API calls.

function debounce(func, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func.apply(this, args), delay);
};
}
const search = debounce((query) => {
console.log(`Searching for ${query}`);
// Imagine an API call here
}, 300);
document.getElementById('searchInput').addEventListener('input', (event) => {
search(event.target.value);
});

Throttling ensures that a function is called at most once in a specified time period.

Use Case: Optimizing scroll event handling

function throttle(func, interval) {
let lastCall = 0;
return function(...args) {
const now = Date.now();
if (now - lastCall >= interval) {
lastCall = now;
func.apply(this, args);
}
};
}
const handleScroll = throttle(() => {
console.log('Scrolled');
// Imagine complex calculations or DOM updates here
}, 300);
window.addEventListener('scroll', handleScroll);

Why Use It: These techniques reduce unnecessary function calls, improving performance and user experience by ensuring that functions are only called when necessary.

9. Memoization

Memoization is an optimization technique that caches the results of expensive function calls and returns the cached result when the same inputs occur again.

Use Case: Improving the performance of recursive functions like Fibonacci calculation.

const memoize = (fn) => {
const cache = {};
return (...args) => {
const key = JSON.stringify(args);
if (!cache[key]) {
cache[key] = fn(...args);
}
return cache[key];
};
};
const fibonacci = memoize((n) => {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
});
console.log(fibonacci(40)); // 102334155

Why Use It: Memoization avoids redundant calculations, significantly improving performance for functions with repeated inputs.

10. Proxy

The Proxy object allows you to create a proxy for another object, enabling you to intercept and redefine fundamental operations such as property lookup, assignment, enumeration, and function invocation.

Use Case: Adding validation and logging on object property access and assignment.

const user = {
name: 'John',
age: 30
};
const handler = {
get: (target, prop) => {
console.log(`Getting ${prop}`);
return target[prop];
},
set: (target, prop, value) => {
if (prop === 'age' && typeof value !== 'number') {
throw new TypeError('Age must be a number');
}
console.log(`Setting ${prop} to ${value}`);
target[prop] = value;
return true;
}
};
const proxyUser = new Proxy(user, handler);
console.log(proxyUser.name); // Getting name, John
proxyUser.age = 35; // Setting age to 35
// proxyUser.age = '35'; // Throws TypeError

Why Use It: Proxies allow for custom behavior for object operations, enhancing control over object manipulation.

Happy coding! 🧙🔮

so that’s it for this article. I hope you all liked it and if you liked it then do not forget to tell us your thoughts in the comment section below.

Feel free to connect on LinkedIn

--

--

MentorAide
MentorAide

No responses yet