JavaScript Best Practices: Objects

John Au-Yeung - Jan 26 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

Like any other programming language, JavaScript has its own list of best practices to make programs easier to read and maintain. There’re lots of tricky parts to JavaScript, so there’re many things to avoid. We can follow some best practices easily to make our JavaScript code easy to read.

In this piece, we look at how to deal with objects in an easily maintainable way. We go through the traps that we can fall into when we define objects.


Use Literals for Primitive Values

In JavaScript, there’re multiple ways to declare primitive variables. Primitive variables include variables of any type other than objects.

One way is to use literals like so:

let x = 1;  
let y = true;  
let z = '';
Enter fullscreen mode Exit fullscreen mode

In the code above, we set the literal value for number, boolean, and string to each variable.

Alternatively, we can write:

let x = new Number(1);  
let y = new Boolean(true);  
let z = new String('');
Enter fullscreen mode Exit fullscreen mode

We can also write:

let x = Number(1);  
let y = Boolean(true);  
let z = String('');
Enter fullscreen mode Exit fullscreen mode

Of the three ways to declare primitive variables above, some ways are better than the others. The best ways are to set the literals directly. The other way is to use the functions as we have in the third example.

Why shouldn’t we use the constructor to create variables with primitive values? First, anything defined with the new operator will have the type ‘object’ even though they have primitive values. This makes comparison between these objects difficult.

For example, if we write:

new String('foo') === new String('foo')
Enter fullscreen mode Exit fullscreen mode

We get false because they’re both of type ‘object’, and === will evaluate to false if two objects don’t have the same reference in JavaScript. This means comparison is difficult.

Comparing with == will also evaluate to false for the same reason.

Since they’re both of type ‘object’, it’s harder to know whether they’re actually strings, booleans, or numbers.

The other two ways are much better because they’ll get us the right type. For example, the following will get us the type ‘number’:

let x = 2;  
console.log(typeof x);
Enter fullscreen mode Exit fullscreen mode

This also applies to other primitive data types.

There’re no reasons to use the new operator to declare things with primitive values. It just makes life harder.

Using new is also slower since the JavaScript interpreter has to do one more operation than necessary to declare something that has a primitive of type ‘object’.

The Number , String and Boolean functions are useful for converting objects from one type to another. For example, if we have:

let x = '2';
Enter fullscreen mode Exit fullscreen mode

Then we can convert it to a number with a Number function as follows:

let y = Number(x);
Enter fullscreen mode Exit fullscreen mode

Use Literals to Declare Objects Whenever They Exist

Some objects have literals associated with them. For example, arrays have the [...] literal. Regular expressions can be declared by surround patterns with slashes. Functions can be declared with the function keyword or using the fat arrow.

It’s confusing to define values with constructors sometimes. For example, arrays have two constructors. One has one parameter with the array length as the parameter. The other is a comma-separated list of entries.

This means that Array(1) will get us an empty array with length 1 and no content. On the other hand, Array(1,2,3) will get us [1,2,3].

As we can see, it’s just not as clear to declare an array by using the constructor.

For functions, we have the function keyword or Function constructor.

Using the Function constructor doesn’t make sense since we have to pass strings that have the code for our functions and strings for the parameter names. It opens things up for code injection attacks, and it’s a pain to write code as a string.

The function keyword is much more clear. And it lets us write code that’s recognized by text editors as function code. There’s no reason to declare a function with the Function constructor unless we want to define a function that has dynamic code.

Likewise, the RegExp constructor is good for constructing regular expression objects dynamically, but otherwise is the same as the regular expression literal. The regular expression literal and constructor are the same for static regular expressions, so there’s some use for the constructor.

The Object constructor just makes us type more code than object literals; otherwise, they’re the same. This means it’s kind of pointless to use it to declare objects.


Automatic Type Conversions

For primitive values, JavaScript can convert things to different types depending on the context.

For example, suppose we have:

1 == '1'
Enter fullscreen mode Exit fullscreen mode

Then the string 1 will be converted to a number.

Suppose we have:

1 + '1'
Enter fullscreen mode Exit fullscreen mode

Then the number 1 will be converted to a string so that we get '11'. JavaScript just assumes that we’re concatenating.

On the other hand, suppose we write:

1 - '1'
Enter fullscreen mode Exit fullscreen mode

We get 0 because it assumes that we’re subtracting two numbers.

Suppose we write:

1 - 'a'
Enter fullscreen mode Exit fullscreen mode

Because the result isn’t a number, we get NaN since we can’t subtract a number with a non-numeric string.

In an expression that evaluates to a boolean, the variables or values inside are evaluated to their truthy or falsy values.

Falsy values include:

  • 0
  • null
  • undefined
  • empty string
  • false
  • NaN

Everything else is truthy. Suppose we have the following:

0 || undefined || null || 1
Enter fullscreen mode Exit fullscreen mode

We get 1. The JavaScript interpreter evaluates all the falsy values and returns 1 since that’s the last thing left.

To make sure we get the types we expect, we should convert everything to the type that we actually expect or we should check for the type.

To convert primitive values like numbers, booleans, and strings, we can use the Number , Boolean , and String functions respectively. We just pass in whatever objects to these functions.

We can also use the + sign before something to convert it to a number.

!! also converts things to boolean according to their truthiness. The first exclamation mark converts the value according to its truthiness and then negates it. Then the second exclamation mark converts it back to the original truthiness value.

To check the type of primitive values, we can use the typeof operator. However, note that null has the type ‘object’. Everything has the type that we expect.


In most cases, object literals are the clearest way to define objects. The only exceptions are when we need functions with dynamically generated code or regular expressions that are dynamically generated. We should never use the new keyword to declare things that have primitive values. Finally, we should be careful of automatic type conversions and check the types or convert them according to our needs.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .