Categories
JavaScript Best Practices

JavaScript Best Practices — Functions

Spread the love

JavaScript is a very forgiving language. It’s easy to write code that runs but has mistakes in it.

In this article, we’ll take a look at some best practices for defining and using functions.

Never Declare a Function in a Non-Function Block

A function should never be defined in a non-function block like a if block or within loops.

Functions within loops tend to cause errors since functions create a closure around the loop.

For instance, if we have the following code:

const funcs = []
for (var i = 0; i < 10; i++) {
  funcs[i] = () => i
}

for (const f of funcs) {
  console.log(f());
}

The code above would log 10 10 times because we declared the loop variable with var , so the last value, which is 10, will be returned in each function that’s in the funcs array.

We don’t want that, so we shouldn’t declare functions on the fly inside non-function blocks.

Use Function Expressions Inside Blocks

Function expressions can’t be used before they’re defined. This means that if they’re in blocks, then they can’t be used before they’re defined within the block.

Also, function declarations within blocks aren’t valid JavaScript syntax, so they shouldn’t be defined inside blocks.

If we want to define a function within a block, then we’ve to use function expressions.

For instance, we can define one within an if block as follows:

if (true) {
  const foo = () => {
    console.log('foo.');
  }
}

The code above is valid JavaScript syntax, so we used const to define it so it’s only available within the block.

Therefore, we should remember to define functions as function expressions instead of using function declarations in blocks.

Never name a parameter arguments

We should never name function parameters with the name arguments since arguments is a special object that’s available within a traditional function.

If we have a parameter arguments , then that’ll overwrite the value of arguments with the value of the arguments parameter.

For instance, if we have the following code:

function foo(arguments) {
  console.log(arguments);
}

foo(1)

Then the value of arguments is 1. On the other hand, if we have the following code:

function foo() {
  console.log(arguments);
}

foo(1)

Then we get the actual arguments object, which is:

Arguments [1, callee: ƒ, Symbol(Symbol.iterator): ƒ]

according to the console log output. It has the argument that we passed in and an iterator to iterate through the items or convert it to an array via Array.from or the spread operator.

Therefore, we should name our parameter something other than arguments .

Never Use arguments, Use Rest Syntax ... Instead

With the introduction of the rest operator, the arguments object is pretty much useless.

The rest operator takes the arguments that we passed in and put them into an array if it has been assigned to a parameter. It works with both arrow functions and traditional functions

On the other hand, the arguments object is only available within traditional functions and it’s an iterable array-like object rather than an array.

Therefore, to do anything useful with it, we’ve to convert it to an array, which is inconvenient.

For instance, instead of writing the following:

function foo() {
  console.log(arguments);
}

foo(1)

We should instead write:

function foo(...args) {
  console.log(args);
}

foo(1)

args would be an array with value 1 inside it.

Likewise, we can use arrow functions as follows:

const foo = (...args) => {
  console.log(args);
}

foo(1)

And we get the same result as before.

We can call any array method or do any array operations with rest parameters. For instance, we can write:

const addAll = (...args) => args.reduce((a, b) => a + b, 0)

addAll(1, 2, 3);

to add all the arguments that are passed and add them together with the reduce method.

That’s something that we can’t do with the arguments object directly.

Conclusion

Rest parameters are much better than the arguments object for getting arguments that are passed into a function.

It works with both traditional and arrow functions.

We should never name a parameter with the name arguments since it clashes with the arguments object.

Declaring a function within a non-function isn’t valid syntax, so we shouldn’t do it.

We should only create functions as function expressions inside blocks.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *