Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function declarations should not be placed in blocks. Use a function expression or move the statement to the top of the outer function

I have the following code:

if (typeof console === "object" && typeof console.error === "function") {
    function e(msg) {"use strict"; console.info(msg);}
}

For which jsLint gives the following error:

Function statements should not be placed in blocks. Use a function expression or move the statement to the top of the outer function.

Why is it giving this error and what does it mean?

like image 988
Jamie Hutber Avatar asked Jan 20 '13 17:01

Jamie Hutber


People also ask

Should I use function declaration or function expression?

In short, use function declarations when you want to create a function on the global scope and make it available throughout your code. Use function expressions to limit where the function is available, keep your global scope light, and maintain clean syntax.

Where can the declaration of a function be placed?

Function declarations (or prototypes) are normally inserted either at the top of each file, locally within a function, or in a header file (the . h files).

What is function declaration and expression?

The main difference between a function expression and a function declaration is the function name, which can be omitted in function expressions to create anonymous functions. A function expression can be used as an IIFE (Immediately Invoked Function Expression) which runs as soon as it is defined.


2 Answers

Explanation

From the jsLintErrors page about the warning Function statements should not be placed in blocks:

This error is raised to highlight code that may not work as you expect it to. In most environments Your code will run without error, but maybe not in the way you expect. In some environments it could cause a fatal syntax error.

That's because Function declarations are hoisted to the top of the scope in which they appear.

Therefore, it is not possible to conditionally declare a function with a block statement.

Example

Let's explore issues raised by this problem with a simple example:

if (true) {
    function example() {
        console.log('hello');
    }
}

The best case scenario is that your code is confusing. In the above example, it looks like what you'd like to do is only declare access to the function if the condition is true. However, when the function is hoisted to the top of the scope, it will actually be interpreted like this:

function example() {
    console.log('hello');
}
if (true) {}

This is dangerous because it doesn't look like what you'd expect based on the original code. The conditional block is actually empty (and unnecessary), and everybody has access to the function, regardless of whether the condition evaluates to true or false.

The worst case scenario is that the browser doesn't understand what to do with the nested function and throws a syntax error when trying to use it. This depends on the engine running JavaScript. It seems like Firefox is one such engine. If you run the following code in Firefox, it will throw an error when executing the following code:

if (true) {
    example();
    function example() {
        console.log('hello');
    }
}

If you open up your console, you should see the following error:

ReferenceError: example is not defined

Solution

So how can you fix this?

Use a function assignment instead of a function declaration

Here's a quick breakdown:

// Declaration
function declarationFunction() {}

// Assignment
var assignmentFunction = function() {}

Function Assignments are not hoisted to the top of the scope.
Function Declarations are hoisted to the top of the scope.

So to conditionally set the example function, just assign it within the block like this:

var example;
if (true) {
    example = function() {
        console.log('hello');
    }
}
like image 96
KyleMit Avatar answered Oct 16 '22 18:10

KyleMit


You should not be creating function inside if block. You are much better off doing:

var e = function(){};

if(typeof console === "object" && typeof console.error === "function"){
    e = function (msg){ ... };
}
like image 40
Tomas Kirda Avatar answered Oct 16 '22 17:10

Tomas Kirda