JavaScript Best Practices — Mutations and Security
By: John Au-Yeung
Tags: JavaScript, Software Development, Programming, Technology, Web Development

Photo by JOSHUA COLEMAN on Unsplash

Like any kind of apps, JavaScript apps also have to be written well.

Otherwise, we run into all kinds of issues later on.

In this article, we’ll look at why and how to avoid mutations and complexity.

Also, we look at security issues.

Don’t use Proxy

Proxy adds side effects to object operation, so we may want to avoid them to reduce complexity.

For instance, instead of writing:

const handler = {

get(target, key) {

return Math.max(target[key], Infinity);

}

};

const object = new Proxy(variable, handler);

object.a;

Instead, we create a function:

const bigProperty = (target, key) => {

return Math.min(target[key], Infinity);

}

positiveProperty(object, 'a');

Reduce the use of Rest Parameters

Rest parameters are handy because we can pass in any number of arguments into a function.

However, it’s better to have explicit parameters since they’re easier to deal with.

A function with rest parameters doesn’t work well with currying since there is an indefinite number of parameters.

Therefore, instead of using:

const sum = (...nums) => {

return nums.reduce((a, b) => a + b);

}

We write:

const sum = (nums) => {

return nums.reduce((a, b) => a + b);

}

nums is an array in the 2nd example.

Having one fixed parameter is better than an indefinite number of arguments in an array.

Reduce the use of this

The use of this should be reduced since the use of this means we have a mutating internal state.

Also, this is confusing in JavaScript.

Therefore, it’ll be a mess if we use it. The value of this changes according to scope.

The use of throw

We shouldn’t use throw too much. It should be reserved for issues that we can’t resolve in our app.

It also should be used for the most critical errors so that everyone can see them right away.

In other cases, we may want to return data instead of in our function.

So instead of writing:

const throwAnError = () => {

throw new Error('error');

}

We may write:

const returnAnError() {

return new Error('error');

}

No Unused Expressions

We shouldn’t have any unused expressions in our code.

So things like:

1 + 2

shouldn’t be in our code since it’s useless.

Instead, we should assign expressions to a variable or pass them in as arguments of functions to use them.

So we can write:

const sum = 1 + 2;

No valueOf Fields

valueOf fields are useless since it just convert a value stored in an object into a primitive value.

This is a roundabout and confusing way to create primitive values.

Instead, we should just create primitive values instead.

So instead of writing:

const obj = {

value: 200,

valueOf() { return this.value; }

};

We just write:

const a = 200;

Always use new with Error

Error is a constructor, so we should use new with it.

In JavaScript, it’s easy to skip new if the class syntax isn’t used.

We’ll get unexpected results if we forgot it in other places.

So to be consistent, we should use new everywhere, including when we’re creating Error objects.

For instance, instead of writing:

throw Error('foo');

We write:

throw new Error('foo');

Security Risks

There are security risks with things like regular expressions.

We should be careful when using them so that they don’t break our apps.

Regular Expression DoS and Node.js

Node.js has issues with big regular expressions which are checked against long strings.

These big expressions block the event loop and so our app will be stalled until the code finishes running.

Since Node.js is mostly single-threaded, we’ll have issues with big regex checks.

Regex with some attributes like grouping with repetition creates more issues than others.

So if we have an email regex like:

/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/

which has many groups, then Node.js will be slow in checking strings against that regex.

Photo by Scott Webb on Unsplash

Conclusion

We shouldn’t use proxies most of the time to simplify the code.

The use of this should always be reduced so as to reduce confusion and the chance of errors.

Also, we should check if a regex won’t stall our Node.js program before using it.

JavaScript In Plain English

Did you know that we have four publications and a YouTube channel? Find them all at plainenglish.io and subscribe to our YouTube channel!