JavaScript is a very forgiving language. It’s easy to write code that runs but has mistakes in it.
In this article, we look at issues with the with
statement, named capture groups, rejecting errors with Error
object, and using regex literals instead of the RegExp
object.
Remove with
Statements
with
statements are bad. They let us add member objects to the current scope, which makes it impossible to tell what the variable inside the block refers to.
For instance, if we have the following code:
const obj = {
a: 1,
b: 2
};
with(obj) {
a = 3;
}
Then the code is within the with
block is written relative to the obj
object. So a
inside the block is actually referencing obj.a
.
However, we can also declare new variables as follows:
const obj = {
a: 1,
b: 2
};
with(obj) {
let a = 3;
}
which is block-scoped and can’t be accessed outside the with
block.
Or we can declare a variable with var
as follows:
const obj = {
a: 1,
b: 2
};
with(obj) {
var a = 3;
}
which changes obj.a
to 3.
As we can see the scope and of a
varies depending on how we declared the variable inside with
. We’re either modify the obj
object’s properties or we’re declaring a new block-scoped variable if we use let
or const
.
Therefore, the with
block is confusing and shouldn’t be used in our production code.
It doesn’t make writing our code easier, and it just makes our code more confusing to everyone.
Therefore, it should never be used in our code.
Use Named Capture Group in a Regular Expression
Named capture groups are good in regular expressions because it’s clear that where the capture groups are and what they’re checking for.
For instance, we can write something like the following:
const regex = /(?<email>[^@]+@[^.]+..+)/;
In the code above, we have a capture group called email
that has the email regex after it.
Now instead of just having a bunch of symbols in our regex, we know that our regex capture group is checking for an email address.
Then we can retrieve the result of the capture group by using the exec
method as follows:
const result = regex.exec('abc@abc.com').groups.email;
As we can see, the groups
property of the object that’s returned by exec
has the email
property which has the match for our email
capture group.
This is much better than just having a bunch of symbols without a name. We can’t get those with a named property.
Use Error Objects as Promise Rejection Reasons
Using error objects as promise rejection reasons is a good idea because it automatically stores the stack trace.
The stack trace is useful for debugging issues that caused the error since it tells us what functions are called to get to the final error.
If we don’t reject an error, then we have no stack trace and we don’t know what’s been called before the error.
For instance, instead of writing:
Promise.reject('error');
We should write:
Promise.reject(new Error('error'));
If we run both and look at the console log output, we’ll see that the 2nd example has the stack trace in the console log output and the first one doesn’t.
Use Regular Expressions Literals instead of the RegExp Constructor
In JavaScript, there’re 2 ways to construct regexes. One is the regular expression literals like /foo/
. The other way is to create an RegExp
instance like new RegExp('foo');
Regular expressions are shorter and we can’t generate a regex dynamically with literals. The RegExp
constructor takes a string with the regex that we want to create, so we can create a regex dynamically with a string.
However, if we want to add escape characters with the RegExp
constructor, we’ve to add an extra backslash before the escape character so that we can write the escape character in the regex string as follows:
new RegEx('d+$');
Because of the extra complexity, it’s better to use regex literals instead of using the RegExp
constructor. The regex above would be the same as:
/d+$/
if it’s written as a regex literal.
Conclusion
with
statements should never be used in our code since it changes the scope of the variables inside.
Error
objects should be used to reject promises so that we get a stack trace in our console log.
If we construct regexes, we should use the regex literals as it’s simpler. Named capture groups should be used so that we can retrieve the capture group match with a name and also makes the pattern easier to understand.