JavaScript is a very forgiving language. It’s easy to write code that runs but has mistakes in it.
In this article, we’ll look at bad constructs that we shouldn’t use, like manually create wrapper objects for primitive values, octal literals, and assigning parameters to a different value.
No Primitive Wrapper Instances
For strings, numbers, and boolean, we shouldn’t create wrapper objects manually with the new
operator.
They’re needed so that we can call methods of primitive values, where the JavaScript interpreter will automatically create the wrapper and then call the methods. Once it’s done calling the method we want to call, then they’re automatically destroyed.
However, there’s no reason to create them manually. They’re confusing since they have the type 'object'
.
For instance, if we have the following expressions:
typeof new String("foo");
typeof new Number(3);
typeof new Boolean(false);
Then they’ll all return type 'object'
even though we work with them as we do with their primitive counterpart.
To convert them back to primitive values, we’ve to call the valueOf
method on them as follows:
new String("foo").valueOf();
new Number(3).valueOf();
new Boolean(false).valueOf();
to get back the primitive version of those wrapper objects.
We should instead write them out as primitive value literals as follows:
"foo"
3
false
It’s less typing and there’s no confusion about the types.
No Octal Literals
Octal number literals are any numbers that start with a 0. JavaScript treats anything that starts with a 0 as an octal number.
Therefore, 051
is actually 41 in decimal.
This is a source of confusion, so octal numeric literals are deprecated in ES5.
Therefore, if we want to write 51 in our code, then we shouldn’t have a 0 before it.
No Reassignment of Function Parameters
We shouldn’t reassign function parameters to a different value in JavaScript because it’ll mutate the arguments
object. This means that the actual parameters are modified.
It’s easy to make mistakes by reassigning function parameters to a new value. And it makes errors hard to track down.
For instance, we should write code like:
const foo = (x) => {
x = 13;
}
const foo = (x) => {
for (x of baz) {}
}
Instead, we should assign the parameter to a variable inside the function body and then manipulate it as we do in the following code:
const foo = (x) => {
let y = x;
}
const foo = (x) => {
for (const b of baz) {}
}
Don’t Use the __proto__ Property to Access the Prototype of the Given Object
We shouldn’t use the __proto__
property to access the prototype of the object that we’re trying to access this property on.
Instead, we can use the Object.getPrototypeOf
method to access the prototype of the current object.
For instance, instead of writing:
const obj = {};
console.log(obj.__proto__)
We should write:
const obj = {};
console.log(Object.getPrototypeOf(obj))
No Variable Redeclaration
Redeclaring variables are bad. However, it’s possible to do this if we use the var
keyword to declare our variables. We don’t want that to happen because we don’t which value our variable actually has.
For instance, if we have:
var a = 3;
var a = 2;
Then we get that a
is 2 when we log a
below the last line.
Instead, we should declare a variable with let
, then we would get an error is we try to declare 2 variables with 2 different names.
No Assignment in return Statement
In JavaScript, we can do an assignment operation in the same line as the return
statement.
For instance, we can write something like:
const baz = (bar) => {
return foo = bar + 2;
}
In the code above, we have the bar
parameter and we add 2 to it. Then we assigned the sum to foo
and then returned it.
Therefore foo
is 5 and we returned that. However, it might also be a typo because the developer may mean to write ==
or ===
instead of =
.
To make things clearer, we should put an assignment expression on a different line than the return
statement.
We can also put parentheses around the assignment expression to make everyone clear that we’re assigning the value to the left operand first and then returning the left operand as the value.
So we can write:
const baz = (bar) => {
return foo == bar + 2;
}
const baz = (bar) => {
return foo === bar + 2;
}
const baz = (bar) => {
return (foo = bar + 2);
}
instead of what we have above.
Conclusion
We shouldn’t use wrapper objects for primitive values since there’s no value to creating them manually. It only brings confusion to other developers and requires more typing.
Also, we shouldn’t have octal literals in our JavaScript code since they’ve deprecated.
We shouldn’t declare variables with the same name more than once.
Finally, assignment expressions shouldn’t be in return
statements to reduce chance ambiguity.