Sunday, November 22, 2020

Nice JavaScript Features



 

In this post I will review some nice JavaScript tricks that I've lately found when reading the Modern JavaScript course. I have been using JavaScript for several years, but still, I have found some  JavaScript capabilities that I was not aware of. 


In general I'm less interested in advanced JavaScript syntax/internals which is not relevant for a well written code. For example:


console.log('2' + 1) // prints 21
console.log('' || false) //prints false

console.log('' || "yes") //prints yes
console.log('' ?? "yes") //prints empty line


It is nice to know when you look at these statements why do they act the way they do, but when writing a well clean code, one should avoid such a confusing behavior.


In the next sections, I will review the JavaScript items that are more relevant in my opinion.



BigInt


JavaScript numbers support numbers in range -(253-1) up to (253-1).

But, JavaScript has a built-in support for big integers, for example:


const big1 = 1234567890123456789012345678901234567890n
const big2 = 1234567890123456789012345678901234567890n
console.log(big1 + big2)



Debugger


Once in a while, when debugging the JavaScript code in Google Chrome, I've found Google Chrome developer tools getting confused. Even I've added a breakpoint in a specific location in the source, I does not stop there. This is mostly due to Hot-Reload in a debugging session, where the sources are reloaded as new files.

A nice trick to force a breakpoint, is to add the debugger statement in the source itself:

console.log('Hello')
debugger // break here
console.log('World')


Note that this breaks in the debugger statement only if the Google Chrome developer tools window is open.



Simple User Interaction


We all use the alert function to print some debug information, but what about getting input from the user? Turns out that we have built-in functions for that:


const name = window.prompt('Your name?', 'John')
const ok = window.confirm(`Hello ${name}, click OK to continue`)
alert(ok ? 'here we go' : 'quitting')



The prompt function opens a text box with an OK and a Cancel buttons.

The confirm function opens a message with an OK and a Cancel buttons.

We will not use this in a production environment, but it is great for debugging purposes.



Nullish Coalescing


When we want to assign a value to a variable only if the value is defined, we can use the nullish coalescing operator. Unlike the OR (||) operator, it will assign the value only if the value is defined.


console.log(null || undefined || false || 'true') // prints true
console.log(null ?? undefined ?? false ?? 'true') // prints false



Optional Chaining


This is a great solution for nested object properties, when you are not sure of the existence of a property. The optional chaining prevents if-conditions to check if the property exists to avoid the "cannot read property X of undefined".


const user1 = {
name: {
first: 'John',
},
}

const user2 = {}

console.log(user1?.name?.first)
console.log(user2?.name?.first)



Object Conversion


You can control the return value upon conversion of an object to a string and to a number.


function User(name, balance = 20) {
return {
name,
balance,
toString: function () {
return `user ${name}`
},
valueOf: function () {
return balance
},
}
}

const u1 = User('John')
console.log(u1) // prints { name: "John", balance: 20}
console.log('hello ' + u1) // prints hello user John
console.log(100 - u1) // prints 80



forEach method


The forEach method can get not only the array elements, but also the array index, and the array itself.


const colors = ['red', 'blue', 'green']
colors.forEach((color, index, array) => {
console.log(color, index, array)
})



Smart Function Parameters


This is very nice method for a function with many parameters, that we want to dynamically add parameters, without affecting the existing calling code section.


function f({firstName, midName = 'Van', lastName}) {
console.log(firstName, midName, lastName)
}

f({firstName: 'John', lastName: 'Smith'})



Sealing a Property


Javascript enables us to protect an object property. This is done by configuration of the property descriptor.


const obj = {}

Object.defineProperty(obj, "secret", {
value: "You cannot delete or change me",
writable: false,
configurable: false,
enumerable: false,
})

console.log(obj.secret)
delete obj['secret'] // ERROR: Cannot delete property 'secret'
obj.secret = "new value" // ERROR: Cannot assign to read only property 'secret' of object
Object.defineProperty(obj, 'secret', {configurable: true}) // ERROR: cannot redefine property


Some more sealing abilities are listed here.


Final Note


I've wrote this post mostly for myself, but it might be relevant for other senior JavaScript engineers who are, like myself, unaware of these nice JavaScript capabilities.



No comments:

Post a Comment