Categories
JavaScript Best Practices

JavaScript Best Practices — Objects

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 the best way to work with objects in our JavaScript code.

Use Property Value Shorthand

The property value shorthand is a great way to shorten our way that we define our objects.

With it, if the key and value have the same identifier, then we can shorten ut by combining it into one.

For instance, instead of writing the following code:

const x = 1,
  y = 2;

const obj = {
  x: x,
  y: y
};

We can instead write:

const x = 1,
  y = 2;

const obj = {
  x,
  y
};

As we can see, it’s much shorter and easier to read when there’s only one identifier rather than repeating identifiers.

They both set x to 1 and y to 2 within the obj object.

Group Shorthand Properties At the Beginning of the Object

Shorthand properties should be grouped at the beginning of the object so that we can tell that those properties are defined with the shorthand.

For instance, we can write something like the following to define our object:

const x = 1,
  y = 2;

const obj = {
  x,
  y,
  foo: 1,
  bar: 2
};

Then we know that x and y are populated with the shorthand and foo and bar are defined from scratch within the object.

Only Quote Properties That are Invalid Identifiers

We should only quote properties that are invalid identifiers within our object.

This is because valid identifiers don’t need to be quoted so they’re redundant there.

For instance, if we have the following:

const obj = {
  'x': 1
};

Then we don’t need the quote around the x since x is a valid identifier.

A valid identifier is alphanumeric and can’t start with a digit. It can also have an underscore or dollar sign.

In the other hand, if we have the following code:

const obj = {
  'x-1': 1
};

Then we need quotes around x-1 since x-1 isn’t a valid identifier.

Don’t Call Object.prototype Methods Directly

Object.prototype methods like hasOwnProperty , propertyIsEnumerable , and isPrototypeOf shouldn’t be called on the object itself since it may be shadowed by the properties on the object in question.

Our object may have noninherited properties with the same name, or it might have been created without the Object prototype by calling Object.create(null) .

Therefore, to make sure that we can call those methods, we should write something like the following:

const obj = {
  a: 1
};

const hasA = Object.prototype.hasOwnProperty.call(obj, 'a');

In the code above, we called the hasOwnPrototype object instance method by using the call method on Object.prototype.hasOwnProperty .

The first argument is our obj object which is the value of this that we use in the hasOwnProperty method.

The 2nd argument is the argument that we pass into hasOwnProperty .

We can also cache the method with a constant so that we don’t have to do the lookup for the method every time that we call it.

To do that, we can write the following code:

const obj = {
  a: 1
};
const hasProperty = Object.prototype.hasOwnProperty;
const hasA = hasProperty.call(obj, 'a');

In the code above, we cached Object.prototype.hasOwnProperty by assigning it to the hasProperty constant so that we can just use that to call the method.

Photo by Bimata Prathama on Unsplash

Prefer the Object Spread Operator Over Object.assign to Shallow Copy Objects

The spread operator lets us do a shallow copy and merge objects in a way that’s shorter than calling Object.assign .

For instance, instead of writing the following:

const obj = {
  a: 1
};
const obj1 = {
  b: 1
};

const merged = Object.assign({}, obj, obj1);

In the code above, we merged the obj and obj1 objects into an empty object by calling Object.assign . The first argument has the object that we want to merge into.

Therefore, the merged constant would have the value {a: 1, b: 1} .

To do a shallow copy, we write the following code:

const obj = {
  a: 1
};

const copy = Object.assign({}, obj);

In the code above, we make a shallow copy of obj , which just copies the top-level properties and leave other properties referencing the original object, by putting all the properties if obj into an empty object.

Object.assign is once again is called with the empty object as the first argument, which is the object that we’ll put the copied properties into.

Therefore, copy will have the same properties as obj .

With the spread operator, we can do this in a much shorter way. To merge objects, we write:

const obj = {
  a: 1
};
const obj1 = {
  b: 1
};
const merged = {
  ...obj,
  ...obj1
};

The spread operator ... spreads the properties into the object that it’s in.

To do a shallow copy, we write the following:

const obj = {
  a: 1
};
const copy = {
  ...obj
};

It’s the same thing except that we only have one object.

Conclusion

We should use the spread operator to make shallow copies of objects and merge multiple objects into one.

If we have shorthands like the property shorthand, then we should use it.

Finally, don’t call Object.prototype methods directly since they may not exist for various reasons.

Categories
JavaScript Best Practices

JavaScript Best Practices for Writing More Robust Code — Value 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 how to do value checks in less bug-prone ways.

Inequalities

We can compare if something isn’t equal with the following operators in JavaScript:

  • > — greater than
  • < — less than
  • <= — less than or equal to
  • >= — greater than or equal to
  • !== , !=— not equal

If we’re checking that something isn’t equal, then we should use the !== operator since it doesn’t do any kind of type coercion before doing the comparison.

We don’t want JavaScript to automatically convert the types for us so that we can we don’t step into traps caused by automatic type conversion.

The rules for automatic type conversion before comparison with != is complex, so we don’t want to deal with them.

With the other operations, there’re no alternatives that don’t do type conversion before comparison.

Therefore, we should be careful with them. Ideally, we convert all the operands to the same type before comparing so no one will be confused about what type of data the operands have.

For instance, the expression 2 > ‘1’ returns true as JavaScript automatically converts the string '1' into number 1.

This may seem convenient, but we can easily step into traps when we have strings that don’t have numbers or strings that have numbers mixed with other text.

Therefore, we should convert them all to the same type before doing any comparison.

In the example above, we can call the Number factory function to convert them both to numbers before comparing them. We can write:

Number(2) > Number('1')

to make sure that they’re both numbers. This is even more important if one or more operands are variables since we can’t see the value of them directly.

The principles above also apply to the < , <= and >= operators.

Checking for the Existence of Values in an Array

We can check for the existence of a value in an array in a few ways. We can use the array instance’s some or indexOf methods.

The some method checks if a given value exists and returns true if it does and false otherwise.

It takes a callback that takes the array entry as the parameter and returns the condition for the item that we’re looking for.

For instance, we can use it as follows:

const arr = [1, 2, 3];
const hasOne = arr.some(a => a === 1);

In the code above, we have an array arr , then passed in a callback to some , which returns a === 1 to specify that we’re looking for an array entry that equals 1 in the arr .

The callback can also take the index of an array itself and the array as the optional 2nd and 3rd parameters respectively.

Therefore, hasOne is true since 1 is in arr .

We can also use indexOf to check if a value is in the given array. It returns the array index of the element if it exists. If the given item isn’t in the array, then it returns -1.

It takes the item we’re looking for and searches for it by using the === operator. For instance, we can write the following code to use it:

const arr = [1, 2, 3];
const index = arr.indexOf(1);

Then index is 0 since 1 is the first entry of arr .

indexOf can also take an optional starting index as the 2nd argument to make it search from that index on.

For instance, if we write:

const arr = [1, 2, 3];
const index = arr.indexOf(1, 1);

We get that index is -1 because we started searching from index 1 to the end of the array, none of which has 1 as the value.

Conclusion

To check for values in an array, we can use the some or indexOf operator.

If we need to use the comparison operators >= , <= , > , or < , then we should convert the types explicitly ourselves if we don’t know what the operands have so that we know that they’ll be the same type when we compare them.

We don’t want to fall in the traps that are caused by automatic type conversions.

Categories
JavaScript Best Practices

JavaScript Best Practices — Arrow Functions and Constructors

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 arrow functions signatures, spacing, and remembering to call super in a child class constructor.

Arrow Function Arguments

When we define arrow functions, we don’t need parentheses if our function only takes one parameter.

For instance, we can write the following to return something multiplied by 2:

const double = x => x * 2;

In the code above, our double function has a parameter x and return x multiplied by 2.

As we can see, we didn’t have parentheses wrapped around the signature, since it isn’t needed if the arrow function only has one parameter.

The parentheses for an arrow function with only one parameter is optional. We can put it in if we think it makes reading the function clearer. For instance, we can write the following:

const double = (x) => x * 2;

Which is the same as what we have in the previous example.

If our arrow function doesn’t have one parameter, then parentheses are required. For instance, we can write the following functions:

const foo = () => {};
const add = (a, b) => a + b;

In the code above, we have the foo function that has no parameters, so the function signature has to have parentheses wrapped around nothing to indicate that it takes no parameters.

Another example is the add function, which has 2 parameters, so we need parentheses to wrap around the a and b parameters.

Space Before or After an Arrow Function’s Arrow

An arrow function has a fat arrow as part of its function definition. Usually, we have a space character before and after the fat arrow.

For instance, we usually define arrow functions as follows:

const foo = () => {};

In the code above, we have the foo function, which has a space character both before and after the => fat arrow.

This spacing makes our function definition more clear and text that’s spaced out is easier to read than text that has no spaces between them.

Remember to Call super() in Constructors

If we have a class that extends another class in JavaScript, then we’ve to remember to call super so that we won’t get an error when we run our code.

For instance, if we have the following code:

class Animal {
  constructor(type) {
    this.type = type;
  }
}

class Cat extends Animal {
  constructor() {}
}

const cat = new Cat();

Then when we run the code above, we’ll get an error telling us to call the super constructor, something like ‘Uncaught ReferenceError: Must call super constructor in derived class before accessing ‘this’ or returning from derived constructor’.

This is good because we won’t forget to call super in Cat since the code won’t run.

Therefore, we should correct this mistake by writing the following code instead:

class Animal {
  constructor(type) {
    this.type = type;
  }
}

class Cat extends Animal {
  constructor(type) {
    super(type);
  }
}

const cat = new Cat();

In the code above, we called super in the Cat class’s constructor.

Even though JavaScript classes are just syntactic sugar for constructor functions, it does prevent us from making mistakes that are easy to make before we have the class syntax.

We have the extends keyword and the super function instead of calling the call method on the parent constructor to calling the parent constructor in the child constructor using the call method.

As we can see, there’s error checking to stop us from going in the wrong direction by making sure that we call super . Otherwise, the code won’t run.

With the old constructor function syntax, there’s no way to tell if we did anything wrong. Forgetting to call the parent constructor won’t give us any errors with the old syntax. We’ll just get unexpected behavior.

Conclusion

Arrow function signatures may not need parentheses if our arrow function only has one parameter.

Otherwise, if our arrow function has more than one parameter or no parameters, then we need the parentheses.

If we forgot to call super in the constructor in a child class, we’ll get an error, so that we won’t forget to call it since the code won’t run.

This is a great benefit of the class syntax since it has error checking built-in.

Categories
JavaScript Best Practices

JavaScript Best Practices — Whitespaces, Underscores, and Useless Ternary

avaScript 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 useless whitespaces, whether to include underscores in identifier names and useless ternary expressions.

No Trailing Whitespace at the End of Lines

Trailing whitespaces are useless. They may be picked by source control systems which may identifier as a code change.

This causes frustration for developers since they expect real code differences rather than difference in whitespaces.

Trailing whitespaces are just taking up space and they should be removed.

Dangling Underscores in Identifiers

Dangling underscores in identifiers are good as long as they’re used to identify ‘private’ variables.

JavaScript doesn’t have truly private variables, so an underscore is useful for identifying variables that we shouldn’t access.

For instance, in a class, we can add ‘private’ variables that starts with an underscore to identify them that it shouldn’t be accessed.

We can write the code as follows:

class Person {
  constructor(name) {
    this._name = name;
  }

  get name() {
    return this._name;
  }
}

In the code above, we have this._name , which is a member of the Person class that we identify as private. We should instead use the name getter to access the value of this._name .

Therefore, this is useful for identifying a private variable before JavaScript classes have private members.

However, in other places, we shouldn’t be accessing some properties that start or end with underscores directly, like the __proto__ property.

For instance, we shouldn’t be changing the __proto__ property by reassigning it to a different value:

const foo = {};
foo.__proto__ = { a: 1 };

We shouldn’t be getting or setting the __proto__ property directly even though it exists and became a standard since ES6.

The __proto__ property has the prototype of the given object. In the code above, __proto__ has the prototype of foo .

To access the prototype of an object, we can use the Object.getPrototypeOf method as follows:

const foo = {};
const proto = Object.getPrototypeOf(foo);

The getPrototypeOf method returns the prototype, which is in an internal property of the specified object. It does the same thing as accessing the __proto__ property.

To set the prototype of an object, instead of assigning a new value to the __proto__ property, we should create a new object with the Object.create method.

For instance, we can use it as follows:

const bar = {
  a: 1
};
const foo = Object.create(bar);
foo.b = 1;

In the code above, we have the foo object, which is assigned to the object created by the Object.create method.

It sets the __proto__ property of foo to the bar object. Therefore, when we log it, we’ll see that the value of the a property in __proto__ is 1.

Other than identifying private variables in constructors or classes, then we probably shouldn’t use underscores in our code since they’re supposed to identify internal members or properties of a constructor or object.

Don’t Use Ternary Operators in Useless Ways

If we’re using the ternary operator to return true or false only, then we don’t need to use the ternary operator.

Instead, we can just remove the ? and everything else after it.

For instance, if we have the following code:

const foo = num === 1 ? true : false;

Then that just returns true is num is 1. Otherwise, if num isn’t 1, then it returns false .

We don’t need a ternary expression to do that, we can just write the following code:

const foo = num === 1;

num === 1 returns true if num is 1 and false otherwise.

Another example that we can simplify is the following:

const baz = bar ? bar : 1;

In the code above, we check if bar is truthy. If it’s truthy, then we return bar . Otherwise, we return 1. Then it assigns the returned value to baz .

We can simplify that with the || operator, which returns the first truthy operand that this operator is applied to.

If both of them aren’t truthy, then it returns the 2nd operand.

For instance, if we have the following code:

const baz = bar || 1;

Then it assigns bar to baz if it’s truthy. Otherwise, it assigns 1 to baz .

Therefore, this is simpler and does the same thing as the previous example.

Conclusion

Trailing whitespaces are useless and they should be removed. They just show in version control systems as code difference which frustrates developers.

Underscores can be used to identify private members in classes and constructors. However, most other uses are dubious.

Ternary operators that can be simplified, like the ones that returns true or false or check if a value is truthy and then returns itself or something else depending on that can be simplified.

Categories
JavaScript Best Practices

JavaScript Best Practices — ES6 Features and Regex

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 template tag spacing, wrapping regex literals, and arrow function bodies.

Spacing Between Template Tags and Their Literals

Since ES6, with the introduction of template strings, a new kind of function called template tags are introduced.

They only work with template strings. It’s a function that takes a few parameters including the template string itself and its parts.

We use template tags by defining a template literal tag and use it as follows:

const foo = (strings, ...args) => {
  console.log(strings, args);
}
`
const a = 1;
const b = 2;
foo`foo ${a} bar ${b}`

In the code above, we have defined the foo literal tag, which has the strings parameter that has an array of all the parts of the string that are static.

The args parameter is an array with all the values that are interpolated in the string.

Therefore, the value of string according to the console log output is [“foo “, “ bar “, “”, raw: Array(3)] , and the value of args is [1, 2] , which are the 2 values that we interpolated into the string.

Template literal tags are useful for taking the parts of a template string and then returning something from it.

Usually, we don’t have any spaces between the template literal tag name and the template string itself.

As we have in the code above, we have:

foo`foo ${a} bar ${b}`

which has no space between foo and the opening backtick so that it’s clear that we’re calling foo on the template string that immediately follows it.

Wrapping Regex Literals

Regex literals may be wrapped so that we’re clear that we’re calling a method on the regex literal.

For instance, if we want to call the exec function as follows:

const result = /foo/.exec("foo");

Then people may not know that we’re actually calling the exec method on it.

If we wrap the regex literal with parentheses, then we can write the following code:

const result = (/foo/).exec("foo");

Then it may be clearer for some people that we’re calling exec on the /foo/ regex literal.

This syntax is more of an optional suggestion than something that everyone should follow.

Braces in Arrow function Body

Arrow functions are functions that are shorter and don’t bind to variables like this or arguments .

Also, we can’t use them as constructors or use bind , call , or apply on it.

It also lets us write functions in a shorter way. One benefit of it is that if we return something on the same line as the signature of the arrow function, then we don’t need the keyword return to return the item at the end of the function.

Instead, whatever’s at the end of the function is returned.

For multiline arrow functions, the return syntax works the same way as any other function. We would need the return keyword to return something.

For instance, if we have the following code:

const foo = () => 2;

Then 2 is returned by the foo function.

If we want to return an object, we can write the following code:

const foo = () => ({
  a: 1,
  b: 2
});

In the code above, we return the object that we wrapped in parentheses, so when we call foo , we get:

{
  a: 1,
  b: 2
}

returned.

If we have a multiline function, then return syntax works the same way as any other function.

For instance, we write the following code to return something in a multiline function:

const foo = () => {
  return {
    a: 1,
    b: 2
  }
};

In the code above, we have the return statement in the second line of the foo function.

And we get the same result as the previous foo function if we call foo .

Therefore, for functions that return what it’ll return on the first line of the function, then we don’t need braces. Otherwise, we should add braces.

Conclusion

Regex literals may be wrapped in parentheses so that we’re clear that we’re calling a method on it.

Usually, we don’t put spaces between the template tag name and the template string literal so that we’re clear that we’re operating on it.

Arrow functions usually don’t have braces if they return something on the first line.

Otherwise, we need braces and the return keyword to return something.