DEV Community

Cover image for 20 Lesser-known Javascript Features that You Probably Never Used
Syakir
Syakir

Posted on • Originally published at devaradise.com

20 Lesser-known Javascript Features that You Probably Never Used

Read post in original url https://devaradise.com/lesser-known-javascript-features for better navigation

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.

Other posts about 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'
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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' }
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
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
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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!

Top comments (11)

Collapse
 
jonrandy profile image
Jon Randy πŸŽ–οΈ • Edited

!! Bang Bang Operator

There is no such operator, you are merely using the logical not operator (!) twice. Describing it as a single operator merely serves to create misunderstanding as to what is actually going on.

Collapse
 
syakirurahman profile image
Syakir • Edited

Officially, if we only refer to MDN docs, you are right. Its not a new operator. Its just a double NOT operator. But not everyone knows that we can do this, hence i include it here πŸ˜€

Collapse
 
giovannimazzuoccolo profile image
Giovanni Mazzuoccolo

Regarding the name "Bang", as @webjose refer to western movies, here is the truth:

In the 1950s, secretarial dictation and typesetting manuals in America referred to the mark as "bang", perhaps from comic books – where the ! appeared in dialogue bubbles to represent a gun being fired – although the nickname probably emerged from letterpress printing. This "bang" usage is behind the names of the interrobang, an unconventional typographic character, and a shebang, a feature of Unix computer systems. In hacker culture, the exclamation mark is called "bang", "shriek"

en.wikipedia.org/wiki/Exclamation_...

Thread Thread
 
syakirurahman profile image
Syakir

Thank you for the trivia πŸ˜„

Collapse
 
webjose profile image
JosΓ© Pablo RamΓ­rez Vargas

At least rename it to "double negation operators". Bang Bang?? Are we in a western movie? That's messed up. LOL.

Thread Thread
 
syakirurahman profile image
Syakir

If you search in google using that keyword, many people actually call it that way.. i didnt invent that word πŸ˜‚

Thread Thread
 
syakirurahman profile image
Syakir

But hey, lets focus on its function instead of how we should call it, shall we? πŸ˜€

Collapse
 
marcinheniborg profile image
marcinheniborg

This list is great. Thanks @syakirurahman

Collapse
 
syakirurahman profile image
Syakir

You're welcome. hope it helps! πŸ˜„

Collapse
 
snook profile image
Ryan Snook

Thank you, I learned some things to start utilizing more πŸ˜€

Collapse
 
syakirurahman profile image
Syakir

No problem.. Tell me what you learn from here? πŸ˜„