Skip to content

Scoping bug when defining a function from a previous scope #2530

Open
@bobrippling

Description

Minimal repro:

>{ let scope = "first"; function fn() { console.log("in fn, scope = " + scope); } }
=undefined
>scope
Uncaught ReferenceError: "scope" is not defined  // as expected, all good
 at line 1 col 1
scope
^
>fn
=function () { ... } // I believe this is incorrect - functions (specifically the assignment) shouldn't be hoisted out of block scope
>fn()
in fn, scope = first // ignoring the hoisting, this is ok - `scope` is closed-over by `fn`
=undefined
>var scope = "second"; function fn() { console.log("in second fn, scope = " + scope); }
// ^ this appears to replace `fn` with the new definition, but reuse the original fn's scope, as seen next:
=function () { ... }
>fn()
in second fn, scope = first // this should be "scope = second"
=undefined

I believe this bug is the combination of two problems:

  • Replacing a function definition uses its scope and ignores the new function's scope
  • Functions are hoisted out of their block scope

This is visible, for example, when the settings app loads the recorder app - both scripts reference a settings variable, and both define a showMainMenu function. The recorder app's showMainMenu then inherits the settings app's settings, causing bugs/exceptions.


Further details on why I believe the hoisting (of the assignment) shouldn't happen:

function f(){
  if(false){
    function g(){
      console.log("g")
    }
  }
  console.log("g:", g); // undefined
}

as it's equivalent to:

 function f(){
+  var g;
   if(false){
-    function g(){
+    g = function(){
       console.log("g")
     }
   }
   console.log("g:", g); // undefined
 }

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions