Categories
JavaScript Best Practices

Better JavaScript — Function Declarations in Blocks

Spread the love

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 ways to improve our JavaScript code.

Unportable Scoping of Block Function Declarations

We shouldn’t have function declarations inside a block.

This isn’t valid JavaScript but it’s still allowed by most JavaScript engines.

This is because we have problems with the results that it produces.

If we have:

function foo(x) {
  function f() {
    return "bar";
  }
  var result = [];
  if (x) {
    result.push(f());
  }

  result.push(f());
  return result;
}
console.log(foo(true));
console.log(foo(false));

then we get:

["bar", "bar"]
["bar"]

like we expect since we pushed f ‘s returned result to the result array.

But when we have something like:

function f() {
  return "global";
}

function foo(x) {
  var result = [];
  if (x) {
    function f() {
      return "bar";
    }
    result.push(f());
  }
  result.push(f());
  return result;
}
console.log(foo(true));
console.log(foo(false));

Then the 2nd foo call won’t run since f is assumed to be the one inside.

This is something that would trip many people up.

The code function will still be allowed by JavaScript engines, but we get weird results like this.

Functions declarations shouldn’t be inside another block or function, so we should avoid this.

What we should do is either keep the inner function outer, or we can assign it to a local variable.

For instance, we can write:

function f() {
  return "global";
}

function test(x) {
  var result = [];
  if (x) {
    const g = f;
    result.push(g());
  }
  result.push(f());
  return result;
}

Then there won’t be any issues with scoping.

Don’t Create Local Variable with eval

eval should definitely never be used because of its security and performance issues.

Another way that eval is bad is creating local variables with it.

For instance, if we have:

function foo(x) {
  eval("var y = x;");
  return y;
}

console.log(foo("bar"));

Then we see 'bar' logged.

We created the variable y by assigning parameter x to it in the string that we passed into eval .

The problem arises if we make the eval call conditional.

For instance, if we have:

var y = "global";

function foo(x) {
  if (x) {
    eval("var y = 'local';");
  }
  return y;
}
console.log(foo(true));
console.log(foo(false));

then the scoping is done according to the condition that we have in foo .

This is definitely a problem since we’ve to go through the code and the code is a string.

Another way that’s bad is that we have:

var y = "global";

function bar(src) {
  eval(src);
  return y;
}
console.log(bar("var y = 'bar';"));
console.log(bar("var z = 'bar';"));

A string is passed into the bar fucntion and we run eval with it.

This pollutes the bar function’s scope with extra variables defined from the outside.

This is even more confusing.

These are more reasons we shouldn’t use eval for any purpose.

Conclusion

We shouldn’t have function declarations within another block.

It’s not valid JavaScript but it’s still allowed.

Also, we shouldn’t use eval in any situation.

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 *