Categories
JavaScript Best Practices

JavaScript Best Practices — Variable Naming

JavaScript is a very forgiving language. It’s easy to write code that runs but has issues in it.

In this article, we’ll look at best practices for naming JavaScript variables.

Computed-Value Qualifiers in Variable Names

We should name variables that hold computed data with a modifier that the end of the name.

For instance, if we have a variable that calculates a total, then we should have it with the Total at the end of the name.

If it holds the total price of a purchase, for example, we can write priceTotal .

As long as we stick with a convention for the qualifier, then no one will get confused.

Less confusion means easier to read code.

If a computed value goes that the end of the name as a rule, then we can put the modifier before it.

For instance, we can write totalPrice instead.

Common Opposites in Variable Names

If we have variables that hold the opposite data of another, then we should be precise with them.

For instance, if we have a begin variable, then we can have the end variable if it holds the opposite data of the begin variable.

Likewise, there’re also names like min and max , next and previous and so on.

Naming Loop Indexes

Loop indexes should have short variable names like i , j and k as a convention.

For instance, we may write:

for (let i = 0; i < 10; i++) {
  //...
}

However, if we have nested loops, then we may want to name the variables with a more descriptive name to make the loops more readable.

If we have a nested loop, we may write:

for (let eventIndex = 0; eventIndex < 10; eventIndex++) {
  //...
  for (let teamIndex = 0; teamIndex < 10; teamIndex++) {
    //...
  }

}

Naming Status Variables

We should name flags with a descriptive name so that we know what they hold.

For instance, we should have a flag with a name with something like isSystemReady so that we know that the flag is for holding information on whether a system is ready.

Naming Temporary Variables

Temporary variables are used to hold intermediate results of computations.

We shouldn’t treat them casually since they’re still part of the code.

It’s better that we define temporary variables with a descriptive name.

For instance, instead of writing:

const temp = (b ** 2 - 4 * a * c) ** 0.5;
let solutions = [];
solutions[0] = (-b + temp) / (2 * a);
solutions[1] = (-b - temp)

We write:

const discriminant = (b ** 2 - 4 * a * c) ** 0.5;
let solutions = [];
solutions[0] = (-b + discriminant) / (2 * a);
solutions[1] = (-b - discriminant)

Then we know that (b ** 2–4 * a * c) ** 0.5 is the discriminant of the quadratic formula.

Naming Boolean Variables

Booleans also need descriptive names.

There’re a few that pertain to boolean variables. They include done to indicate that something is done.

error to indicate whether we have an error or not.

found to indicate that something we look for is found.

success or ok indicates whether an operation has been successful.

Photo by Yoann Boyer on Unsplash

Give Boolean Variables Names that Imply true or false

The names above are good because they imply that they can only be true or false.

We may also want to put is in front of a variable to indicate that it’s a boolean.

For instance, we can define isFound instead of found ,

Use Positive Boolean Variable Names

Double negative expressions are hard on our brains. So we should have positive variable names like found instead of notFound .

Naming Constants

Constants usually are named with all upper case with underscores separating words.

For instance, we can define MAX_DONUTS to hold the maximum number of donuts someone can eat.

Why Have Conventions?

We should follow conventions to that things are easy to read and understand since people don’t have to switch context all the time.

It also prevents us from calling the same things with different names.

Conventions for names can also compensate for language weaknesses. So since JavaScript doesn’t have data type annotations, we can specify the type in the name.

Relationships among items are also indicated with consistent naming schemes.

Conclusion

We should name things with descriptive names and don’t use double negatives.

The only exceptions are loop indexes since often use letters for the names.

Constants should be all uppercase with underscores separating them.

Categories
JavaScript Best Practices

JavaScript Best Practices for Writing More Robust Code — Deep Checks

JavaScript is an easy to learn programming language. It’s easy to write programs that run and does something. However, it’s hard to account for all the uses cases and write robust JavaScript code.

In this article, we’ll look at ways to find items in arrays that aren’t primitive values or items inside non-array iterable objects.

Finding Array Items That aren’t Primitive Values

To find array items that aren’t primitive values, we can’t use the indexOf method as it compares the values using the === operator when it’s doing the search.

Instead, we need to use the find or findIndex method. Both methods take a callback that takes the array entry as a parameter and returns a boolean expression with the condition of the element that we’re looking for.

The find method returns the first occurrence of an object with the given condition.

For instance, we can use the find method as follows:

const arr = [{
    user: 'foo',
    active: true
  },
  {
    user: 'bar',
    active: false
  },
];
const user = arr.find(a => a.active);

In the code above, we have the arr array with objects that have the user and active properties.

Then we used the find method to find the first occurrence of an object that has active set to true .

Then we should see that user is {user: “foo”, active: true} because that’s the first one that has active set to true .

The callback for the find method can also take the array index that’s being looped through and the array itself as the 2nd and 3rd parameters respectively.

It can also take an object that’ll be set as the value of this in the callback as an optional 2nd argument if we wish to change it.

findIndex is like find except that it returns the index of the entry of the first occurrence of something with the condition returned in the callback.

For instance, we can use it as follows:

const arr = [{
    user: 'foo',
    active: true
  },
  {
    user: 'bar',
    active: false
  },
];
const index = arr.findIndex(a => a.active);

Then index is 0 since that’s the first entry that has the active property set to true .

The arguments for findIndex is the same as find . Also, the callback parameters are also the same as find .

Finding Items That are In Non-Array Iterable Objects

We can find items that are in non-array iterable objects by converting them to arrays first and then using an array instance’s methods to find an item.

For instance, we can use this strategy to find items in a NodeList object since it’s a non-array iterable object.

We can convert a NodeList into an array by using the spread operator. For instance, we can write the following code to find an item with the class foo as follows:

const foo = [...document.body.children].find(c => c.className === 'foo')

In the code above, we want to search for the element with the class foo from the given HTML:

<p class='foo'>
  foo
</p>
<p>
  bar
</p>
<p>
  baz
</p>

We do that by getting the child elements of document.body by using the children property, which is a NodeList. A NodeList isn’t an array, but it’s an iterable object.

Therefore, we can use the spread operator to convert it to an array and then do the search with the array instance’s find method to do the search.

In the callback, we check for the className property of the element to see if it’s 'foo' .

Since we do have an element with class foo , find will return the element with such a class.

Therefore, the value of variable foo is the HTML element object with the class 'foo' .

For array-like objects that aren’t iterable. That is, objects that has the length property and numbers as keys, we can use the Array.from to convert it to an object.

For instance, we if we have:

const arrLike = {
  0: 'foo',
  1: 'bar',
  2: 'baz',
  3: 'qux',
  length: 5
};

Then we can write:

const arr = Array.from(arrLike);

to convert it to an array. Then we can use array instance methods to do the searches.

Conclusion

If we want to search for items that aren’t primitive values, then we can use the find or findIndex to search for items. They take callbacks so that we can use them to look for items in the given array.

To search for items in array-like or non-array iterable objects, we can convert them to arrays with the Array.from or the spread operator respective. This way, we can use array methods to look for items.

Categories
JavaScript Best Practices

JavaScript Best Practices for Writing More Robust Code — Checking Object Types

JavaScript is an easy to learn programming language. It’s easy to write programs that run and does something. However, it’s hard to account for all the uses cases and write robust JavaScript code.

In this article, we’ll look at how to check the types for objects so that we only work on the type of objects we’re looking for.

instanceof Operator

The JavaScript instanceof operator lets us get the constructor that’s used to create the object.

The syntax for the instanceof operator is the following:

x instanceof Ctor

Where x is the object that we’re checking and Ctor is the constructor that we want to check if it’s created from it.

For instance, we can use it as follows:

function C() {}  
const c = new C();  
console.log(c instanceof C);

The code above has a new constructor function C and we created the c object by invoking the C constructor with the new operator.

Therefore, when we log c instanceof C , then we should see true because c was created from the C constructor.

Note that most objects are also an instance of Object unless we created an object specifically without a prototype.

Therefore, console.log(c instanceof Object); should also be true as we didn’t specifically remove the prototype when we created c.

The instanceof operator checks all the way up the prototype chain, so if it finds the constructor anywhere up the prototype chain, it’ll return true .

Since Object is a prototype of C and c is an instance of C , instanceof returned true .

We have to be careful when we want to check something isn’t an instance of something.

If we want to check if c isn’t an instance of C , we should write:

if (!(c instanceof C)) {  
  //...  
}

instead of:

if (!c instanceof C) {  
  //...  
}

This is because the ! operator is only applied to c rather than c instanceof C in the 2nd example. Therefore, we get false instanceof C instead of !(c instanceof C) since c is truthy and we negated it.

Constructor Name Check

An alternative to instanceof is to check the name of the constructor that created the object with the constructor.name property of an object.

For instance, if we have:

function C() {}  
const c = new C();  
console.log(c.constructor.name);

Then c.constructor.name is 'C' because we created c from the C constructor.

This only returns the name of the constructor that it’s created with so we won’t get any information about anything up the prototype chain.

Structure Checks

To check if the object is what we want to work with, we should also check if a given property and value exists.

We can do that with the object instance’s hasOwnProperty method, or we can check if the type of the property is 'undefined' or not.

It only checks if a property is an own property, which means that it’s not a property inherited from an object up the prototype chain.

For instance, we can write the following code to check that:

const obj = {};  
obj.foo = 42;  
console.log(obj.hasOwnProperty('foo'));

In the code above, we have obj.hasOwnProperty(‘foo’) . Since obj has the property foo , obj.hasOwnProperty(‘foo’) returns true .

hasOwnProperty will return true even if the value of the property is null or undefined . As long as it’s added to the object, it’ll return true .

Also, we can use the JavaScript in operator to check if a property is in an object.

The in property is used to check whether an inherited or own property is included in a given object.

For instance, if we have:

const obj = {};  
obj.foo = 42;  
console.log('foo' in obj);  
console.log('constructor' in obj);

Then both console logs show true because 'foo' is an own property of obj , while 'constructor' is a property that’s inherited from Object , which is a prototype of obj .

Like with hasOwnProperty , the in operator also returns true if the value of a property is null or undefined .

If we want to check if a property isn’t null or undefined , we can write the following:

const obj = {};  
obj.foo = 42;  
console.log(typeof obj.foo !== 'undefined' && obj.foo !== null);

In the code above, we have:

typeof obj.foo !== 'undefined' && obj.foo !== null

to check if obj.foo isn’t undefined with the typoef operator and check is obj.foo isn’t null with the !== operator.

Conclusion

We can check if an object is an instance of a constructor by using the instanceof operator or using the constructor.name property of an object.

Also, we have to check if a property is what we’re looking for so that we know that we’re working on the right object. To do that, we can use hasOwnProperty , in , or typeof operators.

Categories
JavaScript Best Practices

JavaScript Best Practices for Writing More Robust Code — Checking for Unexpected Values

JavaScript is an easy to learn programming language. It’s easy to write programs that run and does something. However, it’s hard to account for all the uses cases and write robust JavaScript code.

In this article, we’ll look at ways to check for unexpected values, including null and NaN .

Checking for null

null is also a value that we may unexpectedly encounter, so we should also check for that.

Checking for null is a bit tricky since we can’t use the typeof operator to check for null as typeof null returns 'object' .

However, we can still use the === operator or the Object.is method to check for null .

We can use the === operator to check for null as follows:

if (foo === null) {  
  //...  
}

In the code above, we just use the === operator to check for null as we would do for any other value.

The === operator doesn’t do any data type coercion, so it’ll compare the value as-is with any data type conversions before doing the comparison.

Therefore, the code above will work for null comparisons since it doesn’t try to convert null to anything else before doing the comparison.

Object.is is a static object method that takes 2 arguments that take 2 objects that are to be compared.

It’ll return true is both arguments are null , so we can use that for checking if something is null .

To check for null with Object.is , we can write the following code:

if (Object.is(foo, null)) {  
  //...  
}

In the code above, we called Object.is with foo and null . Then if foo is null , Object.is will return true .

Check if a Value is NaN

NaN is a value that we’ll encounter if we try to convert something that’s not a number into a number or if we try to divide 0 or a non-number by 0.

There’re many ways to check for NaN , including the isNaN function, the Number.isNaN method, and Object.is .

The === and == operators won’t work because NaN is considered to be different from itself if we use these operators. Therefore NaN === NaN and NaN == NaN both return false .

However, there’re still many options to check for NaN .

The globalisNaN function can be used to check if a value is NaN or not. Data type coercion is done before checking for NaN with this function.

If we pass in something that will be NaN if we convert it to a number, then isNaN will return true . Otherwise, it’ll return false .

For instance, if we have:

isNaN(NaN);         
isNaN(undefined);  
isNaN({});

then they all return true since they all return NaN if we try to convert them to a number.

On the other hand, if we have:

isNaN(true);        
isNaN(null);

These will return true since true coerces to 1 and null coerces to 0 before being compared with isNaN to check if it’s NaN .

Also, the following returns true :

isNaN('456ABC');

since parseInt(‘456ABC’); returns 456, but Number('456ABC') returns NaN .

The Number.isNaN function checks if a value is NaN but doesn’t try to convert it to a number before doing the comparison. This method is new to ES2015.

For instance, we can use that for comparing value as follows:

Number.isNaN(NaN);          
Number.isNaN(Number.NaN);   
Number.isNaN('foo' / 0);  
Number.isNaN(0 / 0);

They all return true since all the expressions that we put into the argument are evaluated to NaN .

Anything that isn’t NaN will return false , so expressions like:

Number.isNaN('foo');

will return false in addition to numbers in the argument. It only checks if the value is NaN without trying to convert a number first.

Likewise, we can use the Object.is method to check if a value is NaN . Like Number.isNaN , it won’t try to do any data type coercion before doing the equality comparison with NaN .

Object.is considers NaN to be equal to itself, so we can use it to check for NaN .

Therefore, we can use it as we do with isNaN . For instance, we can write:

Object.is(NaN, NaN);  
Object.is`(Number.NaN, NaN);` Object.is`('foo' / 0, NaN);  
`Object.is`(0 / 0, NaN);`

will all return true . Anything that isn’t explicitly evaluated as NaN will returns false when comparing against NaN will Object.is . For instance:

Number.isNaN('foo');

returns false .

Conclusion

Checking for null and NaN have their own tricks. We can use === to check for null , in addition to Object.is .

To check for NaN , we can’t use === to check for NaN as NaN === NaN returns false . However, we can use Object.is , isNaN or Number.isNaN to do the comparison.

Categories
JavaScript Best Practices

JavaScript Best Practices — Avoid Variables Bad Practices

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 how to avoid some bad practices when declaring variables.

Don’t Chain Variable Assignments

Variable assignments shouldn’t be chained because we create global variables in some of the variables in the chain.

For instance, if we write the following code to declare multiple variables in a chain as follows:

{
  let a = b = c = 5;
}

Then a would be declared as a block-scoped variable with let . However, the let keyword doesn’t apply to b and c .

They’re all declared as global variables. This is definitely something that we don’t want.

Therefore, we should avoid the chain of assignments that we have above. Instead, we should write to them all in their own line as follows:

{
  let a = 5
  let b = a;
  let c = a;
}

In the code above, we declared the variable a in the same way, we did in the previous example, but we put the declarations of b and c into their own line.

We assigned the value of a to b and also to c . This way, they’re all block-scoped and we won’t be declaring global variables accidentally.

Avoid Using Unary Increments and Decrements (++, --)

We should avoid unary increment and decrement statements since they’re subject to automatic semicolon insertion, which we don’t want since semicolons may be added to places that we don’t expect them to.

Not using increment and decrement operators also prevents us from incrementing and decrementing values unintentionally which causes unexpected behaviors in our programs.

Therefore, if we have the following code:

let num = 1;
num++;

Then should change it to the following:

let num = 1;
num += 1;

This is better since it’s a statement rather than an expression, so we can’t do something like:

let num = 1;
const foo = num++;

foo is still 1 since the latest value isn’t returned if ++ or -- comes after the variable.

We wouldn’t be able to do the same thing with:

num += 1;

so it’s a lot safer since it’s harder to do an assignment with the line above without creating a new line.

Avoid Linebreaks Before or After = in an Assignment. If the Expression We’re Assigning is Long, Surround Them in Parentheses

If we want to assign a long JavaScript expression to a variable, then we should wrap them in parentheses instead of using line breaks. Line breaks aren’t as clear as parentheses in delimiting expressions.

For instance, instead of writing the following:

let str =
  'The quick brown fox jumps over the lazy dog';

We should instead write:

let str = (
  'The quick brown fox jumps over the lazy dog'
);

This way, we make our code clear that the long string is one expression.

No Unused Variables

Unused variables are dead code and dead code shouldn’t be in our production code.

Since it’s unused then they should be removed. They take up space and confuse readers.

Therefore, instead of writing:

let unusedVar = 1;

We should remove it.

var Declarations Get Hoisted

var declarations are hoisted to the top of their closest enclosing function scope, but their assignment isn’t.

This is something that many developers don’t expect since they don’t have the complete understanding of var .

For instance, if we have the following code:

const foo = () => {
  console.log(x);
  var x = 1;
  console.log(x);
}

foo();

Then x is undefined in the first console log but it’s 1 in the second. If we log it before foo is declared then we get the ‘Uncaught ReferenceError: x is not defined’ error and the function won’t run.

Therefore, the declaration is hoisted onto the top of the function but the value isn’t.

This is an annoying feature of JavaScript which tricks a lot of people. It’s not all that useful, so let and const declarations don’t have this characteristic.

It’s one more reason that we should use let and const instead of var .

Conclusion

var declarations are tricky, so they shouldn’t be used. Dead code like unused variables should be removed.

Variable assignment chains are also tricky since the middleware variables are all declared as global variables, so we should assign them all in their own line.

Finally, increment and decrement operators shouldn’t be used since they both return the new value if it comes before the operand and does the assignment. It’s also subject to automatic semicolon insertion, which does things that we may not expect.