10 JavaScript Tricks You Need To Know About
Welcome back to the exciting world of JavaScript tricks! In this second part of our series, we’re diving deeper into the realm of code magic. This time, we’ve got another set of mind-bending code snippets that will not only improve your codebase but also expand your JavaScript knowledge through practical examples. So let’s get started with these 25 JavaScript tricks that you absolutely need to know about!.
Trick #1: Extract Deep Values from Nested Objects
Have you ever needed to retrieve a value buried deep within a complex object structure? This trick is your key to unlocking those hidden values with ease. Leveraging the power of the Array.reduce
method, this function allows you to access deeply nested values within objects, arrays, and even JavaScript Maps.
function getDeepValue(obj, path) {
path = Array.isArray(path) ? path : path.split('.');
const value = path.reduce(
(obj, key) =>
// prevents error on retrieving key in undefined
obj === undefined
? null
: // check if Map otherwise it is object like
obj instanceof Map
? obj.get(key) ?? obj[key]
: obj[key],
dict,
);
return value === undefined ? null : value;
}
const data = {
person: {
name: {
first: 'John',
last: 'Doe'
}
}
};
const lastName = getDeepValue(data, 'person.name.last'); // 'Doe'
Trick #2: Powerful Date Formatting
JavaScript’s Date
object is already quite powerful, but with a little extra knowledge, you can make it even more versatile. Check out this snippet that showcases a date formatter capable of handling internationalization. You can easily modify and extend it to suit your project's specific needs.
function formatDate(date, formatStr = 'MMMM DD, YYYY', lang = 'default') {
date = new Date(date);
const day = date.toLocaleString(lang, { weekday: 'long' });
const month = date.toLocaleString(lang, { month: 'long' });
const firstDayOfYear = new Date(date.getFullYear(), 0, 1);
const pastDaysOfYear = (date - firstDayOfYear) / 86400000; // one day;
const week = Math.ceil((pastDaysOfYear + firstDayOfYear.getDay() + 1) / 7);
return formatStr
.replace(/\bYYYY\b/g, date.getFullYear())
.replace(/\bYY\b/g, `${date.getFullYear()}`.substring(2))
.replace(/\bWW\b/g, week.toString().padStart(2, '0'))
.replace(/\bW\b/g, week)
.replace(/\bDDDD\b/g, day)
.replace(/\bDDD\b/g, day.substring(0, 3))
.replace(/\bDD\b/g, date.getDate().toString().padStart(2, '0'))
.replace(/\bD\b/g, date.getDate())
.replace(/\bMMMM\b/g, month)
.replace(/\bMMM\b/g, month.substring(0, 3))
.replace(/\bMM\b/g, (date.getMonth() + 1).toString().padStart(2, '0'))
.replace(/\bM\b/g, date.getMonth() + 1);
}
const formattedDate = formatDate(Date.now(), 'MMMM DD, YYYY', 'en'); // August 16, 2023
Trick #3: Node.js-style Promisify for the Browser
Node.js developers are familiar with the convenience of the util.promisify
function. Now you can have that same convenience in the browser! This utility function transforms any function, whether it's asynchronous, callback-based, or synchronous, into a promise-based function.
function promisify(func) {
return (...args) =>
new Promise(async (resolve, reject) => {
const callbackHandler = (...results) => {
// filter error from results to remove dependency on error, result order
const { error, result } = results.reduce((obj, res) => {
if (res instanceof Error) {
obj['error'] = res;
} else {
obj['result'] = res;
}
return obj;
}, {});
if (error) {
reject(error);
} else {
resolve(result);
}
};
try {
const result = await subject(...args, callbackHandler);
resolve(result); // only runs if callbackHandler does not resolve the promise
} catch (error) {
reject(error);
}
});
}
const asyncAdd = promisify(add);
const asyncDivide = promisify(divide);
asyncDivide(8, 2)
.then(result => {
console.log(result); // 4
})
.catch(error => {
console.error(error); // Handle error
});
Trick #4: Deep Object Merging
Merging objects while maintaining their structure can be a headache, especially when dealing with deeply nested data. This neat snippet uses recursion to deeply merge objects and arrays, providing you with a clean, new copy of the merged data.
function deepMerge(a, b) {
if (a === null || typeof a !== 'object') return b ?? {};
if (b === null || typeof b !== 'object') return a ?? {};
const obj = Array.isArray(a) ? [...a] : a;
for (const key in b) {
if (b.hasOwnProperty(key)) {
obj[key] = mergeObjects(obj[key], b[key]);
}
}
return obj;
}
const merged = deepMerge(obj1, obj2);
Trick #5: Compare Complex Data Types with Ease
Comparing complex data types like maps, sets, and objects can be challenging. This trick simplifies the process, making it easy to determine if two objects are structurally equivalent.
function isEqual(a, b) {
// handles primitives and same instances
if (a === b) return true;
switch (`${typeof a}:${typeof b}`) {
case 'symbol:symbol':
return isEqualSymbols(a, b);
case 'function:function':
return isEqualFunctions(a, b);
case 'object:object':
// inner cases for objects other than Array and Object
if (a instanceof Map) return isEqualMap(a, b);
if (a instanceof Set) return isEqualSet(a, b);
// handles Object and Array
const keysA = Object.keys(a);
const keysB = Object.keys(b);
if (keysA.length != keysB.length) return false;
for (let key of keysA) {
if (!keysB.includes(key) || !isEqual(a[key], b[key])) return false;
}
return true;
default:
// handles when a and b is of different types
return false;
}
}
const result = isEqual(obj1, obj2); // true or false
Trick #6: Access Element Siblings with Ease
Navigating through elements and their siblings can be tedious. This trick provides a clean way to access element siblings using a simple utility function.
function element(selectorOrElement) {
const element =
selectorOrElement instanceof Element
? selectorOrElement
: document.body.querySelector(selectorOrElement);
return {
get self() {
return element;
},
get nextElement() {
return element.nextElementSibling;
},
get prevElement() {
return element.previousElementSibling;
},
get siblings() {
return [...element.parentNode.children].filter((el) => el !== element);
},
get nextSiblings() {
const siblings = [];
let nextElement = element.nextElementSibling;
while (nextElement) {
siblings.push(nextElement);
nextElement = nextElement.nextElementSibling;
}
return siblings;
},
get previousSiblings() {
const siblings = [];
[...element.parentNode.children].some((el) => {
if (el !== element) siblings.push(el);
return el === element;
});
return siblings;
},
};
}
const thirdListItemSiblings = element('ul li:nth-child(3)').siblings;
Trick #7: Capitalize Text in JavaScript
While CSS provides various ways to capitalize text, JavaScript doesn’t offer a built-in solution. This compact function brings text capitalization to JavaScript.
function capitalizeText(text) {
return str.replace(/(\w+)/g, (_, word) => word[0].toUpperCase() + word.substring(1) -));
}
const capitalized = capitalizeText('hello world'); // 'Hello World'
Trick #8: Universal Looping with forEach
Looping through different types of data structures using the same mechanism simplifies code. This snippet introduces a universal forEach
function that works with arrays, strings, objects, sets, and more.
function forEach(list, callback) {
if(!list || typeof list !== 'object') return;
const entries = list instanceof Map || list instanceof Set
? Array.from(list.entries())
: list instanceof Iterator
? list
: Object.entries(list);
let index = 0;
for(const item of entries) {
let res = false;
if(Array.isArray(item)) {
res = callback(item[1], item[0] || index++, list);
} else {
res = callback(item, index++, list);
}
if(res === true) break;
}
}
forEach([1, 2, 3], console.log); // array
forEach('123', console.log); // string
forEach({ a: 1, b: 2 }, console.log); // object
Trick #9: Map Any Data Type with map
JavaScript’s Array.map
is incredibly useful, but what if you could apply it to any data type? This trick introduces a utility function that brings the power of map
to various iterable objects.
function map(list, callback) {
list = ({}).toString.call(list) === '[object Object]'
? Object.values(list) : list;
return Array.from(list, callback)
}
map([1, 2, 3], handler); // array
map('123', handler); // string
map({ a: 1, b: 2 }, handler); // object
Trick #10: Filter Any Data Type with filter
Just like mapping, filtering data from non-array data structures can be challenging. This trick presents a filter
function that lets you filter data from arrays, strings, objects, and more.
function filter(list, callback) {
const newList = [];
return (() => {
forEach(list, (...args) => {
const res = callback(...args);
if(Boolean(res)) {
newList.push(args[0]);
}
})
return newList;
})()
}
filter([2, 4, 7, 13, 89], n => n > 7); // returns [ 13, 89 ]
Originally published at https://kkupgrader.eu.org.