Every developer make mistake some time when writing apps. This is a normal part of the development process. There are some mistakes that are made more often than others. It is good to be aware of them so that they can be corrected before it’s made. Once we can do that then we can develop apps a lot easier and become a proficient JavaScript developer since we can develop apps that makes less bugs. We will go through some of the more common bugs that are made so we can avoid them here
In JavaScript, single equal, double equal, and tripe equal all have their own meanings. Single equal sign is the assignment operator which assigns the value on the left to the variable to the right. Double equal sign is the equality check operator which checks an object’s content for equality without checking its type. The triple equals operator checks an object’s content and the type for equality.
We use the single equal assignment operator like the following:
let a = 1
This is used for setting variable values, so it’s we use single equal in a place that shouldn’t be used like in:
if (a = 1){ ... }
then we would be assigning 1 to a
which is always true
. This means that the code inside the if
statement always runs. That’s definitely not what we want.
Double equal sign shouldn’t be too too much since it doesn’t check the type of the object when checking for equality, so something like:
1 == '1'
if true
. This creates problems because if we are only checking for number 1 and we get string with 1 in it, it’s still true. We want to convert them to the same type and then compare them with ===
to check for equality to avoid ambiguity. So if we want to compare if all forms of 1 are equal to each other we convert them to number first by using:
Number(1) === Number('1')
1
wouldn’t be equal to '1'
is we use ===
since they are different types. This would make things a lot more clear. If we want to make sure something aren’t equal to each other then we can use !==
to check if they don’t have the same content or the same type, so:
1 !== '1'
would be true
.
Nested statements and functions in each other means that there’re multiple levels of brackets in each file. Usually, apps are pretty complex so the levels can add up. This means that mismatching brackets is easy if you use a text editor that doesn’t support syntax highlight or check for mismatched brackets. This can easily be avoided with modern text editors such as Visual Studio Code, Atom, and Sublime. If we want to use simpler text editors, then use linters and code formatting tools like ESLint and Prettier to detect these issues. They also let us format code automatically and detect common style issues that may occur like quote style inconsistencies, number of characters in a line, functions that can be shortened, etc.
JavaScript lets us use single quotes, double quotes, and backticks for strings. They are equivalent. However, we should open and close with the same character. So if we open a string with single quote then use single quote to close a string, and if we started with double quotes or backticks, then use those to close the string respectively. Also, special characters like quotation marks have to escape to be included in a string in some cases. If you open a string with single quotes, then if you use single quotes in a string, then you have to escape that to include it in the string. This also applies to double quotes and backticks. If you use double quotes in a double quoted string then you have to escape it. And if you use a backtick in a template string, then you have to escape the backtick character.
In if
statements, parentheses always have to wrap around the whole condition. For example, something like:
if (x > y) && (y < 10) {...}
won’t work. The correct way to write that statement is to write is:
if ((x > y) && (y < 10)) {...}
if we want to check that both conditions are true.
Semicolons are optional at the end of a JavaScript line. However, to make things clear for other people, we should include it so that people know where a line ends. We can use a code linter or formatter like ESLint or Prettier to do this automatically. Lots of text editors also have add-ons to fix it automatically for you.
JavaScript code is case-sensitive, so things that have different capitalization will be considered different even if they have the same spelling. Anything that references them also have to be capitalized correctly. For example, getElementsByTagName
should always be spelled this way with exact same capitalization. The general convention in JavaScript is that we spell variables and function names with camel case, so we should stick with that for consistency if we define our own variables.
It’s important that we reference code that have been defined and loaded before hand in order to use the code. If we are using script tag then before we reference the code, we have to load the code first. So the script tag that references the script with the variable we want to use should come before the script tag that references the script that has the code that we want to reference.
Fortunately, JavaScript modules are much more common nowadays, so that we just have to remember to export the code that you want to use in another module and the import the exported variable in the module that you want to use the variable before referencing it. JavaScript modules solves a lot problems with script tags. Global variables do not have to used much anymore to let different scripts reference the same variable, and also we can make variables private without the use of closures since we only need to export the ones that are needed elsewhere.
In JavaScript, there are many reserved words that cannot be used as variable names. They shouldn’t be used as variable names since they collide the name of the reserved words, creating confusion with the JavaScript interpreter. To avoid this we should use names that are descriptive like firstName
, lastName
, and things like that.
We shouldn’t use global variables whenever possible. This means that all variables we declare should use the let
or const
keywords for variables and constants respectively. This avoids issues with global variable scope and overwriting global variable data. It also let us avoid errors from assigning to entities that should be constant or assigning things accidentally that are global.
When functions are called with expected parameters missing, then unexpected results may be returned because you passed in unexpected input to a function.We have to make sure that we pass in the right parameters to a function so that we get the right results. It also a good idea to check for unexpected parameters if the function is used in lots of places like functions that are in libraries so that we can deal with unexpected parameters gracefully like ending the execution of the function when parameters passed in are of an invalid type or null
or undefined
.
JavaScript arrays starts with index 0, so the last index of an array will always be 1 less than the length
of the array. When you pass in an index that is beyond the length or it’s invalid like a negative number, we get undefined
, so we will get ReferenceErrors if we try to get the invalid entry and do stuff with it.
null
and undefined
are things that are often the values of variables. This means that we have to check for these when we are getting something by traversing the nested properties of objects or looping through an array. When we have null
or undefined
we want to handle them gracefully. This means that we should always check for them. So we if have an object called foo
and we want to access deeply nested properties within it, then we should check for null
or undefined
in each level, like so:
if (foo && foo.bar && foo.bar.baz){ ... }
This way we know that all the properties are defined so that we can get access the baz
property. For arrays if we want to access index i
, we should check if it’s defined by writing:
if (arr[i]){...}
so that we won’t get unexpected undefined errors.
The optional chaining operator (?.
) is being worked on, so hopefully it will be finalized soon and we can use it to access deeply nested properties in an object and we don’t have to deal with properties being undefined as much anymore. Also, Lodash has a get
function, which can try to access deeply properties of arrays and objects and get the value if it exists or return null
if there’s anything undefined in the middle of the object’s hierarchy. This is much better than a long chain of undefined
or null
checks.
JavaScript has both undefined
and null
for non-values. However, there are quite a few differences between the two. undefined
means that the variable may have been declared, but nothing is set to it. A variable can also be explicitly set as undefined
. The type of an undefined
variable, when checking the type with the typeof
operator, will get us the type 'undefined'
. Functions that don’t return anything returns undefined
. On the other hand, null
values have to be explicitly set by functions that return null
or just set directly to a variable. When we check an object that has the null
value set, we’ll find that the type of it is'object'
if a variable has the null
value.
For this reason, it’s probably easier to stick to undefined
whenever we can when we’re setting variable values to non-values. It reduces confusion and we only have to check that the type of a variable is 'undefined'
to see whether it’s undefined
. That’s less painful than having two checks, for both null
and undefined
.
To write functions that return undefined
, we don’t have to do anything like the following example:
const f = () => {}
To set a variable that was assigned some other value to undefined
, we can write:
x = undefined;
To check if a property value is undefine
, we can write:
typeof obj.prop === 'undefined'
or
obj.prop === undefined
To check if a variable is undefined
, we can write the following code:
typeof x === 'undefined'
A declared variable that hasn’t been assigned anything automatically has the value undefined
.
If we have to check for null
, then we can write:
obj.prop === null
or
x === null
for variables. We can’t use the typeof
operator for checking null
because the data type of null
is 'object'
.
In JavaScript, the +
operator is used for both adding two numbers and concatenating strings together. Because JavaScript is a dynamic language, the operands are all automatically converted to the same type before the operation is applied. For example, if we have:
let x = 1 + 1;
then we get two because they’re both numbers. The +
operation was used for addition like we expected. However, if we have the following expression:
let x = 1 + '1';
then we get '11'
because the first operand was coerced into a string before the +
operation is applied. The +
operation was used for concatenation instead of addition. When we use the +
operator on multiple variables, this makes knowing the type even harder. For example, if we have:
let x = 1;
let y = 2;
let z = x + y;
as we expect, we get three because x
and y
are both numbers. On the other hand, if we have:
let x = 1;
let y = '2';
let z = x + y;
then we get '12'
because y
is a string, so the +
operator was used for concatenation instead. To solve this issue, we should convert all the operands to numbers first before using them with the +
operator. For example, we should rewrite the above example into the following:
let x = 1;
let y = '2';
let z = Number(x) + Number(y);
The code above will get us 3 as the value of z
since we converted them both to numbers with the Number
factory function first. The Number
function takes in any object and returns a number if it can be parsed into a number, or NaN
otherwise. An alternative way to do this is to use the new Number(...).valueOf()
function, as we do in the following code:
let x = 1;
let y = '2';
let z = new Number(x).valueOf() + new Number(y).valueOf();
Since new Number(...)
is a constructor that creates an object
type, we want to use the valueOf
function to convert it back to a primitive type to make sure that what we get is a number type. A shorter way to do this is to write:
let x = 1;
let y = '2';
let z = +x + +y;
The +
sign in front of a single operand will try to convert the single operand into a number or toNaN
if it can’t be converted into a number. It does the same thing as the Number
function. We can also convert a variable to a particular type of number. The Number
object has a parseInt
function to convert an object into an integer and a parseFloat
function to convert an object into a floating-point number. parseInt
takes the object you want to convert to a number as the first argument. It also takes a radix as an optional second argument, which is the base of the mathematical numeral systems. If the string starts with 0x
, then the radix will be set to 16. If the string starts with anything else, then the radix will be set to 10.
We can use them as in the following examples:
let x = 1;
let y = '2';
let z = Number.parseInt(x) + Number.parseInt(y)
Also, we can use the parseFloat
function as in the following code:
let x = 1;
let y = '2';
let z = Number.parseFloat(x) + Number.parseFloat(y)
We will get 3 in both of the examples above.
JavaScript closes a statement at the end, so one line code is considered distinct from the other. For example, if we have:
const add = (a, b) => {
return
a + b;
}
we get undefined
if we run console.log(add(1, 2));
since we ran the return
statement, which ended the function execution, before a + b
is run. Therefore, a + b
will never be run in this function. To fix this, we either have to put the return
statement all in one line or use parentheses to surround what we want to return. For example, we can write:
const add = (a, b) => {
return a + b;
}
This will log 3 if we run console.log(add(1, 2));
since we are actually returning the computed result in the function. We can also write:
const add = (a, b) => {
return (
a + b
);
}
This is handy for returning expressions that might be longer than one line. This will also log 3 if we run console.log(add(1, 2));
. For arrow functions, we can also write:
const add = (a, b) => a + b
for single-line functions since the return
statement is implicit for single-line arrow functions. We can also write:
const add = (a, b) => (a + b)
to get the same thing. This also works for single-line arrow functions.
In JavaScript, if a statement is incomplete, like the first line of:
const power = (a) => {
const
power = 10;
return a ** 10;
}
inside the function then the JavaScript interpreter will run the first line together with the second line to get the full statement. So:
const
power = 10;
is the same as:
const power = 10;
However, for complete statements like return
statements, the JavaScript interpreter will treat them as separate lines. So:
return
a ** 10;
is not the same as:
return a ** 10;
Even though JavaScript is a friendly language, it’s still very easy to make mistakes when writing JavaScript code. It’s easy to confuse undefined
and null
when we aren’t familiar with JavaScript. Because of the dynamic typing nature of JavaScript, operators like the +
operator that can do multiple things can easily be converted to a type we don’t expect and produce the wrong result. Also, if statements can be complete on their own, then they shouldn’t be written in their own lines if we want both lines to be together.
Yes, that is all. I hope this tutorial will surely help and you if you liked this tutorial, please consider sharing it with others. Thank you !
#JavaScript #React #Angular #Programming #Functional Programming