Traps we can fall into when we define objects
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
One way is to use literals like so:
let x = 1;
let y = true;
let z = '';
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('');
We can also write:
let x = Number(1);
let y = Boolean(true);
let z = String('');
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')
false because they’re both of type ‘object’, and
=== will evaluate to
== 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;
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.
Boolean functions are useful for converting objects from one type to another. For example, if we have:
let x = '2';
Then we can convert it to a number with a
Number function as follows:
let y = Number(x);
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
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 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.
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.
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.
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 example, suppose we have:
1 == '1'
Then the string 1 will be converted to a number.
Suppose we have:
1 + '1'
Then the number 1 will be converted to a string so that we get
On the other hand, suppose we write:
1 - '1'
We get 0 because it assumes that we’re subtracting two numbers.
Suppose we write:
1 - 'a'
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:
- empty string
Everything else is truthy. Suppose we have the following:
0 || undefined || null || 1
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
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.