Best practices on hoisting and function calls

Best practices on hoisting and function calls
0

#1

I’d like some feedback on this. I’ve read not long ago that we should, when possible, avoid hoisting, that is calling a function before that function is defined. I find that for readibility I want to call functions before they are created a lot, that putting the function first would make my code confusing if someone else would read it. I’m going to show an example of something I’m doing now:

 const request = new XMLHttpRequest();

 request.onload = outputResponse;
 request.open('get', searchParameter, true)
 request.send()


 function outputResponse() {
   const image = document.getElementById("avatar");
   const userInfo = document.querySelector(".user-info");
   let responseObj = JSON.parse(this.responseText);
  ...
  etc

So in this case, if I were to put the function first, it feels out of context, you would have to get to the end of it and see the “request.onload = outputResponse;” to get it. Should I still place the function first?

Thanks for any advice on this.


#2

I’m not sure where you read that, but it’s 1) not quite accurate and 2) not really an issue with functions. It’s not bad advice, though.

The short answer: you will prevent some frustrating bugs by declaring all of your variables at the top of their scope. If you’re using function declarations (ie function outputResponse() { //... }), then it’s not going to matter. It is possible for you to run into trouble by trying to call a function expression before it’s defined (ie var someFunction = function() { //... }).

Like ‘closure’, ‘hoisting’ is one of those terms that’s not entirely understood by everyone who uses JavaScript. Let’s start from the beginning: hoisting is not something you do, it’s something the compiler does. Compilation is complicated, but we can focus on two stages defined by the ECMAScript (JavaScript) spec. First, the compiler gets all of the declarations in your code and binds them to their execution context. When using var, that execution context is the function it’s executed in.

function someFunction() {
  var aVariable; //execution context is someFunction
}

This is true even if the variable is declared inside of another non-function code block, like an if clause:

function someFunction() {
   if(true) {
      var someVariable; // execution context is still someFunction
   }
}

This is what “hoisting” refers to. It means that no matter how far down in the function the variable someVariable is declared, and no matter if it’s in another non-function code block, it’s going to be accessible to any other code executed in someFunction. It’s as if the variable declaration has been moved to the top. Function declarations are also dealt with in this first stage, so they will always be defined in their execution context before they are invoked.

note: let and const are block scoped, so their execution context is not the function they’re defined in, but any code block.

The problem that your given advice is trying to save you from comes because the compiler doesn’t assign values to those declarations until this stage is done and all of the declarations have their execution context.

function someFunction() {
   console.log(aVariable); // console.log() has access to the variable aVariable because it's been "hoisted", but it doesn't have access to its value so this will output "undefined"
   if(true) {
      var aVariable = "Tacos";
       console.log(aVariable); // now it can output the string because the variable has been initialized with a value
   }
}

Here are some (perhaps better) resources on the subject:



#3

Actually I just remembered, it’s said in the “Javascript: Understanding the weird parts” Udemy course by Anthony Alicea. Execution context and hoisting was very well explained there and I felt like I got it, but at the end he said that, yea, to avoid it if possible as a good practice to avoid posible future frustrations. I’m still not sure if in my case I should revert the code order in favor of this advice, or not, in favor of readability. I will follow your advice than in this case, it doesn’t matter. Thanks again.


#4

From airbnb styleguide:

7.1 Use named function expressions instead of function declarations

Why? Function declarations are hoisted, which means that it’s easy - too easy - to reference the function before it is defined in the file. This harms readability and maintainability. If you find that a function’s definition is large or complex enough that it is interfering with understanding the rest of the file, then perhaps it’s time to extract it to its own module! Don’t forget to name the expression - anonymous functions can make it harder to locate the problem in an Error’s call stack.

also airbnb point of view on:
hoisting
variables