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.

Categories
JavaScript Best Practices

JavaScript Best Practices for Writing More Robust Code — Arrays and Iteration

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 better ways to manipulate arrays and looping through them.

Use the for…of Loop

The for...of loop is a loop that’s introduced with ES2015 to iterate through each entry of an iterable object.

This loop is the best loop for looping through all entries of an iterable object because it works with any kinds of iterable objects, including arrays, the arguments object, maps, sets, and DOM Node lists.

It’s much better than the regular for loop and the while loop because we don’t have to worry about setting the indexes and loop conditions.

All we have to do is to use the for...of loop and reference the object that we want to loop through.

For instance, we can use it to loop through an array as follows:

const arr = [1, 2, 3];
for (const a of arr) {
  console.log(a);
}

In the code above, we used the for...of loop on the arr array to loop through all the entries of arr .

Another good thing about using for...of is that we can use const to make sure that we can’t change the entry that’s being looped through, which is a .

This is a feature that isn’t available with any other kinds of loops.

We can also loop through other iterable objects like maps as follows:

const map = new Map([
  ['a', 1],
  ['b', 2]
]);
for (const [key, value] of map) {
  console.log(key, value);
}

In the code above, we created a new Map instance. Then we can loop through the map object and extract the key and value with the destructuring syntax as we did above.

The for...of loop is the only kind of JavaScript loop that lets us destructure items right inside the loop.

The destructuring syntax lets us extract the items easily and clearly. Therefore, it’s less error-prone than regular for or while loops as we can do a lot all in one line while retaining the clarity of our code.

Use Array.isArray() to Check If a Variable is an Array

Array.isArray() is the most reliable method to check if a variable or a value is an array.

It’s the most reliable method to determine if something is an array because it works for arrays from different iframes or document objects.

We should use this instead of alternatives like instanceof because of the possibility of having multiple global objects existing.

Multiple iframes and tabs will have multiple Array objects, and their Array.prototype property will all be different. To make sure that we check through all of them, we have to use Array.isArray instead of arr instanceof Array .

Checking the constructor property has the same problem as the instanceof check.

Therefore, we should use Array.isArray to check if a value or variable is an array since it checks all global Array objects to see if it’s an instance of them.

For instance, we can use it as follows:

const foo = [1, 2, 3];
const isArray = Array.isArray(foo);

In the code above, we just called Array.isArray on foo , which returns true if foo is an array and false otherwise.

Therefore, isArray should be true since foo is an array.

Photo by Dušan Smetana on Unsplash

Array Instance’s Map Method

Array instance methods are there for a good reason. They are very useful for manipulating the array instance or returning something derived from the array instance.

The map method lets us convert all the values of the array instance and return a new array with all the existing array instance’s values converted with the callback function that we pass into the map method.

Using map is better than using loops and pushing entries to a new array for example since we write less code to do the same thing.

Therefore, there’s no reason not to use a cleaner way with map than using loops.

For example, we can use it as follows:

const arr = [1, 2, 3];
const doubled = arr.map(x => x * 2);

In the code above, we called map on arr with the callback x => x * 2 to double every entry of arr , put them all in a new array in the same order, and return it.

Therefore, doubled is:

[
  2,
  4,
  6
]

Conclusion

To write robust code that deals with arrays, we should use the for...of loop to loop through all entries of an iterable object.

This way, we don’t have to deal with indexes and loop conditions, and it works with all iterable objects.

Also, the destructuring syntax works with it.

The most reliable way to check if a variable or a value is an array is the Array.isArray method since it works for situations where multiple versions of a global object exist when dealing with iframes.

Finally, the array instance’s map method is the best way to convert all values of an original array to new ones by returning the new one.