Andy Tran
Andy Tran

Reputation: 155

Does this function have closure over this block?

I am experimenting with closures but rather than enclosing a function within a function, I enclosed a function within a block. Since functions are not blocked-scoped and will be hoisted outside of the block I assumed that it wouldn't have access to the scope within the block. Yet, in this case, the function returns the block-scoped variable. Does this mean that the function is a closure?

{
   let a = 'hi'
   function test() {
      return a
   }
}
test() // hi

Upvotes: 3

Views: 160

Answers (1)

Ray Toal
Ray Toal

Reputation: 88428

I'd be happy to call it a closure, at least according to Wikpedia's definition:

Operationally, a closure is a record storing a function together with an environment. The environment is a mapping associating each free variable of the function (variables that are used locally, but defined in an enclosing scope) with the value or reference to which the name was bound when the closure was created. Unlike a plain function, a closure allows the function to access those captured variables through the closure's copies of their values or references, even when the function is invoked outside their scope.

In your function test, the variable a is a free variable, used by the function but not defined inside the function. When you called the function outside the block, it retained the value of a. So, you've met the essential points of the definition of closure (according to Wikipedia).

Of course, you asked the question because it's kind of tricky. Normally with closures, we define a function inside an environment and then "export" it out by binding the function object to a name that has a wider scope. Because of the way JavaScript treats function declarations defined in a block (see Code Maniac's link to the ECMAScript specification on handling block-scoped function declarations) you do get this effect! So it's kind of a closure, even though you never explicitly exported the function.

Of course if you had written

{
   let a = 'hi'
   let test = () => a
}
test()

you get an error.

But this works:

let b;
{
   let a = 'hi'
   let test = () => a
   b = test
}
b() // "hi"

so yes, the block is acting as the non-local environment from which variables can be captured. I'm thinking yes, it's okay to speak of this as being a closure, because it acts like one (even if this behavior comes from a pre-ECMAScript 2015, "optional", and non-strict treatment of function declarations inside of blocks). If it walks like a duck, and all that.

Upvotes: 1

Related Questions