DEV Community

Cover image for 10 JavaScript Tricky Hacks - Part 3
Sayuj Sehgal
Sayuj Sehgal

Posted on

10 JavaScript Tricky Hacks - Part 3

1. Flattening Arrays with flat()

The flat() method in JavaScript is used to flatten arrays. It creates a new array with all sub-array elements concatenated into it recursively up to the specified depth. By default, the depth is 1.

Here's an example:

let arr = [1, 2, [3, 4, [5, 6]]];

console.log(arr.flat());
// Output: [1, 2, 3, 4, [5, 6]]

console.log(arr.flat(2));
// Output: [1, 2, 3, 4, 5, 6]

console.log(arr.flat(Infinity));
// Output: [1, 2, 3, 4, 5, 6]
Enter fullscreen mode Exit fullscreen mode

In the first console.log, we're calling flat() without any arguments, so it defaults to a depth of 1 and only the first level of nested arrays is flattened.

In the second console.log, we're calling flat(2), specifying a depth of 2, so it flattens up to two levels of nested arrays.

In the third console.log, By passing Infinity, it will flatten all nested arrays no matter how deep they are.

2. Using ^ for Swapping Values

The caret (^) symbol in JavaScript is used for bitwise XOR operation. However, it can also be used to swap values between two variables without using a temporary variable. Here's how it works:

let a = 5; // binary: 101
let b = 3; // binary: 011

a = a ^ b; // binary: 110, decimal: 6
b = a ^ b; // binary: 101, decimal: 5
a = a ^ b; // binary: 011, decimal: 3
Enter fullscreen mode Exit fullscreen mode

After these operations, a becomes 3 and b becomes 5, effectively swapping their original values.

Here's the explanation:

  1. a = a ^ b performs a bitwise XOR operation on a and b and assigns the result to a. Now a holds the result of a ^ b.

  2. b = a ^ b is equivalent to b = (a ^ b) ^ b. Since XOR is associative, this is equivalent to b = a ^ (b ^ b). b ^ b is 0, and any number XOR 0 is the number itself, so b becomes a.

  3. a = a ^ b is equivalent to a = (a ^ b) ^ a. This is equivalent to a = b ^ (a ^ a). a ^ a is 0, so a becomes b.

So, the values of a and b are swapped without using a temporary variable. However, this method should be used with caution, as it can lead to unexpected results if a and b are not integers or if they are very large.

3. Converting to Numbers with Unary Plus

In JavaScript, the unary plus (+) operator can be used to convert a string or a boolean into a number. This is a quick and easy way to perform type conversion in JavaScript. Here's how it works:

let str = "123";
let num = +str; // num is now the number 123

console.log(typeof str); // "string"
console.log(typeof num); // "number"

let bool = true;
let numFromBool = +bool; // numFromBool is now the number 1

console.log(typeof bool); // "boolean"
console.log(typeof numFromBool); // "number"
Enter fullscreen mode Exit fullscreen mode

In the above example, the unary plus operator is used to convert a string and a boolean into numbers. The string "123" is converted into the number 123, and the boolean true is converted into the number 1. The typeof operator is used to confirm the type of the variables before and after the conversion.

It's important to note that if the string cannot be parsed into a number, the result will be NaN (Not a Number):

let str = "abc";
let num = +str; // num is now NaN

console.log(num); // NaN
Enter fullscreen mode Exit fullscreen mode

In this case, the string "abc" cannot be parsed into a number, so the result of the unary plus operation is NaN.

4. Using Object.assign() for Merging Objects

In JavaScript, Object.assign() is a method used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object. This method is often used for merging objects (combining properties of two or more objects).

Here's an example:

let obj1 = { a: 1, b: 2 };
let obj2 = { b: 3, c: 4 };

let mergedObj = Object.assign({}, obj1, obj2);

console.log(mergedObj); // { a: 1, b: 3, c: 4 }
Enter fullscreen mode Exit fullscreen mode

In this example, Object.assign() takes three arguments: an empty object {}, obj1, and obj2. It starts by copying all properties from obj1 to the empty object. Then it copies all properties from obj2 to the target object. If a property already exists on the target object (like b in this case), its value is overwritten by the value from the source object (obj2).

So, the resulting mergedObj contains all properties from obj1 and obj2, with the values from obj2 taking precedence.

5. Short-circuiting for Default Values

In JavaScript, you can use the logical OR (||) operator to provide a default value for a variable. This technique is known as short-circuiting. If the value on the left side of the || operator is truthy (i.e., it's a value that is considered true when evaluated in a Boolean context), it will be the result. If it's falsy (i.e., it's a value that is considered false when evaluated in a Boolean context), the value on the right side of the || operator will be the result.

Here's an example:

let name = user.name || 'Anonymous';

console.log(name); // If user.name exists and is not an empty string, null, undefined, 0, NaN, or false, it will be logged. Otherwise, 'Anonymous' will be logged.
Enter fullscreen mode Exit fullscreen mode

In this example, if user.name is defined and is not an empty string, null, undefined, 0, NaN, or false, name will be assigned the value of user.name. If user.name is not defined or is one of those falsy values, name will be assigned the string 'Anonymous'.

This is called short-circuiting because if the first operand is truthy, JavaScript doesn't even look at the second operand—it "short-circuits" the operation and returns the first operand.

6. Dynamically Accessing Object Properties with Bracket Notation

In JavaScript, you can dynamically access object properties using bracket notation. This is particularly useful when you need to access a property whose name is stored in a variable, or when the property name is not a valid identifier (for example, it contains spaces or special characters).

Here's an example:

let person = {
  name: 'John',
  age: 30,
  'favorite color': 'blue'
};

let property = 'name';

console.log(person[property]); // Outputs: 'John'

property = 'age';

console.log(person[property]); // Outputs: 30

console.log(person['favorite color']); // Outputs: 'blue'
Enter fullscreen mode Exit fullscreen mode

In this example, we first define an object person with properties name, age, and favorite color. We then define a variable property and set it to 'name'. When we use person[property], JavaScript looks up the value of property (which is 'name'), and then retrieves the value of the property 'name' from the person object. We can change the value of property to 'age' and access the age property in the same way. We can also directly use a string in the brackets to access properties with names that are not valid identifiers, like 'favorite color'.

7. Template Strings for HTML Fragments

Template strings, also known as template literals, are a feature in JavaScript that allows you to create strings with embedded expressions. They are particularly useful when creating HTML fragments because they allow you to easily insert variables and expressions into your HTML.

Here's an example:

let name = 'John';
let age = 30;

let html = `
  <div>
    <h1>${name}</h1>
    <p>Age: ${age}</p>
  </div>`
;

console.log(html);
Enter fullscreen mode Exit fullscreen mode

In this example, we first define two variables name and age. We then define a template string html that contains an HTML fragment. The template string is enclosed in backticks, and the variables name and age are inserted into the HTML using ${...} syntax. When we log html to the console, it outputs the following HTML:

<div>
    <h1>John</h1>
    <p>Age: 30</p>
  </div>
Enter fullscreen mode Exit fullscreen mode

This feature is very useful when you need to generate HTML dynamically, for example, when building a web page based on data from a server.

8. Using Array.includes() for Presence Check

The Array.includes() method in JavaScript is used to determine whether an array includes a certain value among its entries. It returns true or false as appropriate.

Here's an example:

let array = [1, 2, 3, 4, 5];

console.log(array.includes(2)); // Outputs: true
console.log(array.includes(6)); // Outputs: false
Enter fullscreen mode Exit fullscreen mode

In this example, we have an array of numbers from 1 to 5. We then use the includes() method to check if the number 2 is in the array, which it is, so it returns true. We also check if the number 6 is in the array, which it isn't, so it returns false.

9. Preventing Object Modification

In JavaScript, there are several ways to prevent modification of an object. Here are three methods:

1. Object.preventExtensions(): This method prevents new properties from being added to an object.

let obj = { a: 1 };
Object.preventExtensions(obj);
obj.b = 2; // Attempt to add new property
console.log(obj.b); // Outputs: undefined
Enter fullscreen mode Exit fullscreen mode

2. Object.seal(): This method prevents new properties from being added and existing properties from being removed. However, it allows the modification of existing properties.

let obj = { a: 1 };
Object.seal(obj);
obj.b = 2; // Attempt to add new property
delete obj.a; // Attempt to delete existing property
console.log(obj.b); // Outputs: undefined
console.log(obj.a); // Outputs: 1
Enter fullscreen mode Exit fullscreen mode

3. Object.freeze(): This method prevents new properties from being added, existing properties from being removed, and prevents changing the enumerability, configurability, or writability of existing properties. In essence, it makes the object read-only.

let obj = { a: 1 };
Object.freeze(obj);
obj.b = 2; // Attempt to add new property
obj.a = 3; // Attempt to modify existing property
console.log(obj.b); // Outputs: undefined
console.log(obj.a); // Outputs: 1
Enter fullscreen mode Exit fullscreen mode

In all these examples, trying to modify the object in a way that is not allowed will not throw an error, it will simply not have any effect. However, in strict mode ('use strict';), these actions will throw a TypeError.

10. The Power of Function.prototype.bind()

The Function.prototype.bind() method in JavaScript is a powerful tool that allows you to set the this value in the context of a function, and create a new function with a specific this value and initial arguments.

Here's an example:

let person = {
  firstName: "John",
  lastName: "Doe",
  fullName: function() {
    return this.firstName + " " + this.lastName;
  }
}

let logName = function(location, country) {
  console.log(this.fullName() + " from " + location + ", " + country);
}

// Create a new function with 'this' bound to 'person'
let logPersonName = logName.bind(person);

// Call the new function
logPersonName("New York", "USA"); // Outputs: "John Doe from New York, USA"
Enter fullscreen mode Exit fullscreen mode

In this example, we have a person object with a fullName method. We also have a logName function that logs a message including the person's full name and location.

We then use bind() to create a new function logPersonName where this is bound to the person object. When we call logPersonName, it has access to the person object's fullName method because this is set to person.

This is particularly useful when you want to borrow a method from an object, or when you want to have a function that can be used with different this values.

If you like this blog, you can visit my blog sehgaltech for more content.

Top comments (0)