What is a 'Closure'?

前端 未结 23 1565
星月不相逢
星月不相逢 2020-11-22 08:02

I asked a question about Currying and closures were mentioned. What is a closure? How does it relate to currying?

23条回答
  •  耶瑟儿~
    2020-11-22 09:02

    First of all, contrary to what most of the people here tell you, closure is not a function! So what is it?
    It is a set of symbols defined in a function's "surrounding context" (known as its environment) which make it a CLOSED expression (that is, an expression in which every symbol is defined and has a value, so it can be evaluated).

    For example, when you have a JavaScript function:

    function closed(x) {
      return x + 3;
    }
    

    it is a closed expression because all the symbols occurring in it are defined in it (their meanings are clear), so you can evaluate it. In other words, it is self-contained.

    But if you have a function like this:

    function open(x) {
      return x*y + 3;
    }
    

    it is an open expression because there are symbols in it which have not been defined in it. Namely, y. When looking at this function, we can't tell what y is and what does it mean, we don't know its value, so we cannot evaluate this expression. I.e. we cannot call this function until we tell what y is supposed to mean in it. This y is called a free variable.

    This y begs for a definition, but this definition is not part of the function – it is defined somewhere else, in its "surrounding context" (also known as the environment). At least that's what we hope for :P

    For example, it could be defined globally:

    var y = 7;
    
    function open(x) {
      return x*y + 3;
    }
    

    Or it could be defined in a function which wraps it:

    var global = 2;
    
    function wrapper(y) {
      var w = "unused";
    
      return function(x) {
        return x*y + 3;
      }
    }
    

    The part of the environment which gives the free variables in an expression their meanings, is the closure. It is called this way, because it turns an open expression into a closed one, by supplying these missing definitions for all of its free variables, so that we could evaluate it.

    In the example above, the inner function (which we didn't give a name because we didn't need it) is an open expression because the variable y in it is free – its definition is outside the function, in the function which wraps it. The environment for that anonymous function is the set of variables:

    {
      global: 2,
      w: "unused",
      y: [whatever has been passed to that wrapper function as its parameter `y`]
    }
    

    Now, the closure is that part of this environment which closes the inner function by supplying the definitions for all its free variables. In our case, the only free variable in the inner function was y, so the closure of that function is this subset of its environment:

    {
      y: [whatever has been passed to that wrapper function as its parameter `y`]
    }
    

    The other two symbols defined in the environment are not part of the closure of that function, because it doesn't require them to run. They are not needed to close it.

    More on the theory behind that here: https://stackoverflow.com/a/36878651/434562

    It's worth to note that in the example above, the wrapper function returns its inner function as a value. The moment we call this function can be remote in time from the moment the function has been defined (or created). In particular, its wrapping function is no longer running, and its parameters which has been on the call stack are no longer there :P This makes a problem, because the inner function needs y to be there when it is called! In other words, it requires the variables from its closure to somehow outlive the wrapper function and be there when needed. Therefore, the inner function has to make a snapshot of these variables which make its closure and store them somewhere safe for later use. (Somewhere outside the call stack.)

    And this is why people often confuse the term closure to be that special type of function which can do such snapshots of the external variables they use, or the data structure used to store these variables for later. But I hope you understand now that they are not the closure itself – they're just ways to implement closures in a programming language, or language mechanisms which allows the variables from the function's closure to be there when needed. There's a lot of misconceptions around closures which (unnecessarily) make this subject much more confusing and complicated that it actually is.

提交回复
热议问题