20 Lesser-known Javascript Features that You Probably Never Used

Muhammad Syakirurohman
Frontend Engineer
Published on
20 Lesser-known Javascript Features that You Probably Never Used

JavaScript is a cornerstone of modern web development, powering dynamic websites and applications. While many developers familiar with the basic and widely used features of JavaScript, numerous hidden features often go unnoticed. These lesser-known features can make your code more concise, readable, and powerful.

In this article, we’ll explore some hidden JavaScript features. From the nullish coalescing operator to Map and Set objects, each feature includes practical examples and best practices. Utilizing these features can help you write cleaner, more efficient code and tackle complex problems easily.

Whether you’re a seasoned developer or a beginner, this article will introduce you to underutilized JavaScript capabilities. By the end, you’ll have new techniques to elevate your coding skills with Javascript.

Lesser-known Javascript Features

1. Nullish Coalescing Operator

The nullish coalescing operator (??) is used to provide a default value when a variable is null or undefined.

Code Example:

let foo = null;
let bar = foo ?? 'default value';
console.log(bar); // Output: 'default value'

Use the nullish coalescing operator to handle cases where null or undefined values may appear, ensuring that your code runs smoothly with default values.

2. Optional Chaining

The optional chaining operator (?.) allows safe access to deeply nested object properties, avoiding runtime errors if a property does not exist.

Code Example:

const user = {
	profile: {
		name: 'Alice'
	}
};
const userProfileName = user.profile?.name;
console.log(userProfileName); // Output: 'Alice'
 
const userAccountName = user.account?.name;
console.log(userAccountName); // Output: undefined

Use optional chaining to avoid errors when accessing properties of potentially null or undefined objects, making your code more robust.

3. Numeric Separators

Numeric separators (_) make large numbers more readable by visually separating digits.

Code Example:

const largeNumber = 1_000_000;
console.log(largeNumber); // Output: 1000000

Use numeric separators to improve the readability of large numbers in your code, especially for financial calculations or large datasets.

4. Promise.AllSettled

Promise.allSettled waits for all promises to settle (either fulfilled or rejected) and returns an array of objects describing the outcome.

Code Example:

const promises = [Promise.resolve('Success'), Promise.reject('Error'), Promise.resolve('Another Success')];
 
Promise.allSettled(promises).then((results) => {
	results.forEach((result) => console.log(result));
});
// Output:
// { status: 'fulfilled', value: 'Success' }
// { status: 'rejected', reason: 'Error' }
// { status: 'fulfilled', value: 'Another Success' }

Use Promise.allSettled when you need to handle multiple promises and want to ensure that all results are processed, regardless of individual promise outcomes.

5. Private Class Fields

Private class fields are properties that can only be accessed and modified within the class they are declared.

Code Example:

class MyClass {
	#privateField = 42;
 
	getPrivateField() {
		return this.#privateField;
	}
}
 
const instance = new MyClass();
console.log(instance.getPrivateField()); // Output: 42
console.log(instance.#privateField); // Uncaught Private name #privateField is not defined.

Use private class fields to encapsulate data within a class, ensuring that sensitive data is not exposed or modified outside the class.

6. Logical Assignment Operators

Logical assignment operators (&&=, ||=, ??=) combine logical operators with assignment, providing a concise way to update variables based on a condition.

Code Example:

let a = true;
let b = false;
 
a &&= 'Assigned if true';
b ||= 'Assigned if false';
 
console.log(a); // Output: 'Assigned if true'
console.log(b); // Output: 'Assigned if false'

Use logical assignment operators to simplify conditional assignments, making your code more readable and concise.

7. Labels for Loop and Block Statements

Labels are identifiers followed by a colon, used to label loops or blocks for reference in break or continue statements.

Code Example:

outerLoop: for (let i = 0; i < 3; i++) {
	console.log(`Outer loop iteration ${i}`);
	for (let j = 0; j < 3; j++) {
		if (j === 1) {
			break outerLoop; // Break out of the outer loop
		}
		console.log(`  Inner loop iteration ${j}`);
	}
}
// Output:
// Outer loop iteration 0
//   Inner loop iteration 0
labelBlock: {
	console.log('This will be printed');
	if (true) {
		break labelBlock; // Exit the block
	}
	console.log('This will not be printed');
}
// Output:
// This will be printed

Use labels to control complex loop behavior, making it easier to manage nested loops and improve code clarity.

8. Tagged Template Literals

Tagged template literals allow you to parse template literals with a function, enabling custom processing of string literals.

Code Example 1:

function logWithTimestamp(strings, ...values) {
	const timestamp = new Date().toISOString();
	return (
		`[${timestamp}] ` +
		strings.reduce((result, str, i) => {
			return result + str + (values[i] || '');
		})
	);
}
 
const user = 'JohnDoe';
const action = 'logged in';
console.log(logWithTimestamp`User ${user} has ${action}.`);
// Outputs: [2024-07-10T12:34:56.789Z] User JohnDoe has logged in.

Code Example 2:

function validate(strings, ...values) {
	values.forEach((value, index) => {
		if (typeof value !== 'string') {
			throw new Error(`Invalid input at position ${index + 1}: Expected a string`);
		}
	});
	return strings.reduce((result, str, i) => {
		return result + str + (values[i] || '');
	});
}
 
try {
	const validString = validate`Name: ${'Alice'}, Age: ${25}`;
	console.log(validString); // This will throw an error
} catch (error) {
	console.error(error.message); // Outputs: Invalid input at position 2: Expected a string
}

Use tagged template literals for advanced string processing, such as creating safe HTML templates or localizing strings.

9. Bitwise Operators for Quick Math

Bitwise operators in JavaScript perform operations on binary representations of numbers. They are often used for low-level programming tasks, but they can also be handy for quick mathematical operations.

List of Bitwise Operators

  • & (AND)
  • | (OR)
  • ^ (XOR)
  • ~ (NOT)
  • << (Left shift)
  • >> (Right shift)
  • >>> (Unsigned right shift)

Code Example 1:

You can use the AND operator to check if a number is even or odd.

const isEven = (num) => (num & 1) === 0;
const isOdd = (num) => (num & 1) === 1;
 
console.log(isEven(4)); // Outputs: true
console.log(isOdd(5)); // Outputs: true

Code Example 2:

You can use left shift (<<) and right shift (>>) operators to multiply and divide by powers of 2, respectively.

const multiplyByTwo = (num) => num << 1;
const divideByTwo = (num) => num >> 1;
 
console.log(multiplyByTwo(5)); // Outputs: 10
console.log(divideByTwo(10)); // Outputs: 5

Code Example 3:

You can check if a number is a power of 2 using the AND operator.

const isPowerOfTwo = (num) => num > 0 && (num & (num - 1)) === 0;
 
console.log(isPowerOfTwo(16)); // Outputs: true
console.log(isPowerOfTwo(18)); // Outputs: false

Use bitwise operators for performance-critical applications where low-level binary manipulation is required, or for quick math operations.

10. in Operator for Property Checking

The in operator checks if a property exists in an object.

Code Example:

const obj = { name: 'Alice', age: 25 };
console.log('name' in obj); // Output: true
console.log('height' in obj); // Output: false

Use the in operator to verify the existence of properties in objects, ensuring that your code handles objects with missing properties gracefully.

11. debugger Statement

The debugger statement invokes any available debugging functionality, such as setting a breakpoint in the code.

Code Example:

function checkValue(value) {
	debugger; // Execution will pause here if a debugger is available
	return value > 10;
}
checkValue(15);

Use the debugger statement during development to pause execution and inspect code behavior, helping you identify and fix bugs more efficiently.

12. Chained Assignment

Chained assignment allows you to assign a single value to multiple variables in a single statement.

Code Example:

let a, b, c;
a = b = c = 10;
console.log(a, b, c); // Output: 10 10 10

Use chained assignment for initializing multiple variables with the same value, reducing code redundancy.

13. Dynamic Function Names

Dynamic function names allow you to define functions with names computed at runtime.

Code Example:

const funcName = 'dynamicFunction';
const obj = {
	[funcName]() {
		return 'This is a dynamic function';
	}
};
 
console.log(obj.dynamicFunction()); // Output: 'This is a dynamic function'

Use dynamic function names to create functions with names based on runtime data, enhancing code flexibility and reusability.

14. Get Function Arguments

The arguments object is an array-like object that contains the arguments passed to a function.

Code Example:

function sum() {
	let total = 0;
	for (let i = 0; i < arguments.length; i++) {
		total += arguments[i];
	}
	return total;
}
 
console.log(sum(1, 2, 3)); // Outputs: 6

Use the arguments object to access all arguments passed to a function, useful for functions with variable-length arguments.

15. Unary + Operator

The unary operator (+) converts its operand into a number.

Code Example:

console.log(+'abc'); // Outputs: NaN
console.log(+'123'); // Outputs: 123
console.log(+'45.67'); // Outputs: 45.67 (converted to a number)
 
console.log(+true); // Outputs: 1
console.log(+false); // Outputs: 0
 
console.log(+null); // Outputs: 0
console.log(+undefined); // Outputs: NaN

Use the unary operator for quick type conversion, especially when working with user input or data from external sources.

16. Exponentiation ** Operator

The exponentiation operator (**) performs exponentiation (power) of its operands.

Code Example:

const base = 2;
const exponent = 3;
const result = base ** exponent;
console.log(result); // Output: 8

Use the exponentiation operator for concise and readable mathematical expressions involving powers, such as in scientific or financial calculations.

17. Function Properties

Functions in JavaScript are objects and can have properties.

Code Example 1:

function myFunction() {}
myFunction.description = 'This is a function with a property';
console.log(myFunction.description); // Output: 'This is a function with a property'

Code Example 2:

function trackCount() {
	if (!trackCount.count) {
		trackCount.count = 0;
	}
	trackCount.count++;
	console.log(`Function called ${trackCount.count} times.`);
}
trackCount(); // Outputs: Function called 1 times.
trackCount(); // Outputs: Function called 2 times.
trackCount(); // Outputs: Function called 3 times.

Use function properties to store metadata or configuration related to the function, enhancing the flexibility and organization of your code.

18. Object Getters & Setters

Getters and setters are methods that get or set the value of an object property.

Code Example:

const obj = {
	firstName: 'John',
	lastName: 'Doe',
	_age: 0, // Conventionally use an underscore for the backing property
	get fullName() {
		return `${this.firstName} ${this.lastName}`;
	},
	set age(newAge) {
		if (newAge >= 0 && newAge <= 120) {
			this._age = newAge;
		} else {
			console.log('Invalid age assignment');
		}
	},
	get age() {
		return this._age;
	}
};
 
console.log(obj.fullName); // Outputs: 'John Doe'
obj.age = 30; // Setting the age using the setter
console.log(obj.age); // Outputs: 30
 
obj.age = 150; // Attempting to set an invalid age
// Outputs: 'Invalid age assignment'
console.log(obj.age); // Still Outputs: 30 (previous valid value remains)

Use getters and setters to encapsulate the internal state of an object, providing a controlled way to access and modify properties.

19. !! Bang Bang Operator

The !! (double negation) operator converts a value to its boolean equivalent.

Code Example:

const value = 'abc';
const value1 = 42;
const value2 = '';
const value3 = null;
const value4 = undefined;
const value5 = 0;
 
console.log(!!value); // Outputs: true (truthy value)
console.log(!!value1); // Outputs: true (truthy value)
console.log(!!value2); // Outputs: false (falsy value)
console.log(!!value3); // Outputs: false (falsy value)
console.log(!!value4); // Outputs: false (falsy value)
console.log(!!value5); // Outputs: false (falsy value)

Use the !! operator to quickly convert values to booleans, useful in conditional expressions.

20. Map and Set Objects

Map and Set are collections with unique features. Map holds key-value pairs, and Set holds unique values.

Code Example 1:

// Creating a Map
const myMap = new Map();
 
// Setting key-value pairs
myMap.set('key1', 'value1');
myMap.set(1, 'value2');
myMap.set({}, 'value3');
 
// Getting values from a Map
console.log(myMap.get('key1')); // Outputs: 'value1'
console.log(myMap.get(1)); // Outputs: 'value2'
console.log(myMap.get({})); // Outputs: undefined (different object reference)

Code Example 2:

// Creating a Set
const mySet = new Set();
 
// Adding values to a Set
mySet.add('apple');
mySet.add('banana');
mySet.add('apple'); // Duplicate value, ignored in a Set
 
// Checking size and values
console.log(mySet.size); // Outputs: 2 (only unique values)
console.log(mySet.has('banana')); // Outputs: true
 
// Iterating over a Set
mySet.forEach((value) => {
	console.log(value);
});
// Outputs:
// 'apple'
// 'banana'

Use Map for collections of key-value pairs with any data type as keys, and Set for collections of unique values, providing efficient ways to manage data.

Conclusion

By leveraging these lesser-known JavaScript features, you can write more efficient, readable, and robust code. Start integrating these techniques into your projects to take your JavaScript skills to the next level.

We hope this guide has provided you with valuable insights and practical examples to help you leverage these hidden JavaScript features. Don’t hesitate to experiment with them and see how they can fit into your coding practices.

If you found this article helpful, please share it with your fellow developers and friends. I’d love to hear your thoughts and experiences with these features, so feel free to leave a comment below.

Thanks. Happy coding!