0

I spend lot of time to find out the reason of incorrect function behavior and was really surprized of my investigation result.

I will compress all my complicated logic and will represent using very simple example:

I have some executor:

function run() {

   //define one more fn inside
   function render() {
      //returns execution result
      return 1;
   }

   //I use this execution result
   console.log(render()); //expect 1, but was 2

   //here I have lot of code added by other developers
   //and after some refactoring and code merge was added
   //one more implementtaion

   //it was done by accidentally as merge issue
   function render() {
      return 2;
   }
}

My big surprise that console.log prints 2. Only after detecting second function with the same name I can try to explane this using popular words like hoisting, but I dont understand how this possible in this concrete example.

Also, when second render function assigned to variable then all this code works as expected. This also can't explane using hoisting definition, as first function was not assigned to variable:

function render() {
  //returns execution result
  return 1;
}

console.log(render()); //returns 1

var render = function () {
  return 2;

}

I totally understand that this is buggy code, but I want to understand why this works this way and how not save time with identifying such kind of problems?

VadimB
  • 5,533
  • 2
  • 34
  • 48
  • 1
    How to detect it? run a linter. – epascarello Dec 02 '16 at 15:26
  • [JavaScript function declaration syntax: var fn = function() {} vs function fn() {}](https://stackoverflow.com/questions/336859/javascript-function-declaration-syntax-var-fn-function-vs-function-fn?rq=1) – Andreas Dec 02 '16 at 15:27
  • So, are you asking how hoisting works? – Felix Kling Dec 02 '16 at 15:31
  • No, seems I understand. Functions in javascript behave not the same as variables when declared at the botton of the page. – VadimB Dec 02 '16 at 15:35
  • *"Functions in javascript behave not the same as variables when declared at the botton of the page."* Not sure what that means. The behavior of a function doesn't depend on it's position in the source code. – Felix Kling Dec 02 '16 at 16:39
  • Yes, but variable declared at the bottom (below reqested place) behave not the same as function at the bottom (below reqested place). – VadimB Dec 03 '16 at 12:07

1 Answers1

1

When you define a function in Javascript it is hoisted to the top of the enclosing scope so it doesn't matter where in the scope you put the definition it acts exactly as though they were all at the beginning. However, they still keep their order of definition so if there are multiple functions of the same name then only the last one defined within the scope will be visible.

This explains why your code outputs 2 as the second function hides the first one.

When you assign to a variable using var which has the same name as a function that hides the function and now the usual rules for variable assignment apply.

If instead you had used let (and had a browser that supports let) you would have seen a different result as then the console.log(render()) line would throw an exception for an undefined variable because the let is hoisted (so hides the first function) but the initialisation doesn't happen until after the output.

function render() {
  //returns execution result
  return 1;
}

console.log(render()); //throws exception for undefined variable.

let render = function () {
  return 2;
}

N.B. this is one of the areas that converters from ES2015 to ES5 may get wrong as it is hard to produce efficient ES5 code that can check for undefined variables.

Duncan
  • 92,073
  • 11
  • 122
  • 156