<< JavaScript you Don’t know >> Volume up

  • Definition: Closure occurs when a function can remember and access its lexical scope, even if the function is executed outside the current lexical scope
  • Chestnut:
  function foo() {
    var a = 2;
    function bar() {
      console.log(a) // 2
    }
    bar()
  }
  foo()
Copy the code

Somewhat like nested scopes, the function bar() can access variable A in the outer scope.

  • Is this a closure?
function foo() { var a = 2; function bar() { console.log(a) } return bar; } var baz = foo() baz() // 2 -- this is what closure doesCopy the code

The JS engine has a garbage collector to free up unused memory. Normally foo() would be collected, but the above example obviously cannot be collected because the closure prevents this from happening, leaving its internal scope intact and therefore not being collected.

  • Bar () still holds a reference to the scope, which is called a closure, so baz can finally access variable A.
Function foo() {var a = 2 function baz() {console.log(a) // 2} bar(baz)} function bar(fn) {fn() // This is not a closure} foo()Copy the code

We pass baz to bar, and when we call this internal function (fn), we access A

Var fn function foo() {var a = 2 function baz() {console.log(a)} fn = baz} function bar() {fn() // closure} foo() bar() / / 2Copy the code

Passing an inner function outside of its lexical scope holds a reference to the original definition scope and uses a closure no matter where the function is executed.

  • Does that mean?
function wait(message) { setTimeout(function timer() { console.log(message) },1000) } wait("Hellow,closure!" )Copy the code

Timer passes the value to setTimeout(…) ,timer has coverage of wait (…) Enclosing the closure of the scope, and thus preserving a reference to the variable message, wait(…) After 1000 milliseconds, its internal scope does not disappear, and the timer function still has wait(…). Closure of a scope.

function setupBot(name, selector) {
  $(selector).click(function activator() {
    console.log("Activating:" + name)
  })
}
setupBot("Closure Bot 1", "#bot_1")
setupBot("Closure Bot 2", "#bot_2")
Copy the code

Whenever you use callbacks in timers, event listeners, Ajax requests, cross-window communication, Wed Workers, or other asynchronous (or synchronous) tasks, you’re actually using closures!

  • Is it a closure?
var a = 2
(function IIFE() {
  console.log(a)
})()
Copy the code

It is not a closure in the strict sense, because IIFE is not executed outside of its own lexical scope.

So what exactly is a closure?

In the constructor body, another function is defined as the target object’s method function, which in turn refers to temporary variables in the outer function body. This allows the object to indirectly retain the value of the temporary variable used by the original constructor body as long as the target object retains its method throughout its lifetime. Although the original constructor call has ended and the name of the temporary variable has disappeared, the value of the variable is always referred to in the target object’s method and can only be accessed through this method. Even if the same constructor is called again, only new objects and methods are generated, and the new temporary variables correspond only to the new values, separate from the last call.

  • Function: The ability to use local variables outside the scope of a function definition without contaminating the world.

  • Principle: Based on lexical scope chains and garbage collection, a function scope can be accessed outside the current scope by maintaining references to the function scope, i.e. a closure is a function that can read variables inside other functions.

scope

  • Scope: A set of rules for determining where and how to look for variables (identifiers).
  • Lexical scope: LEXICAL scope is the scope of the definition at the lexical stage. Lexical scope is determined by where code and block scope are written when code is written, so when lexical scope is handled code is left scoped (most of the time).
  • Block scope: Refers to the fact that variables and functions can belong not only to the scope they are in, but also to a code block (usually wrapped in {}). Common block-level scopes are with, try/catch, let, const, etc.
  • Function scope: All variables belonging to this function can be used and reused throughout the function scope (including nested scopes).
  • Scope chain: When looking for a variable, the search starts from the current scope. If it does not find one, the search goes to the parent (lexical parent) scope until it finds the global scope. A scope chain is simply a list containing these scopes.

The purpose of closures

  1. It can read variables inside a function and protect them from being accessed by other means, thus protecting the security of variables.
  2. Maintains a variable in memory and is not garbage collected.
The function f1 () {var n = 520; The function f2 () {the console. The log (n); / / 520}}Copy the code

F1 is the parent of F2, and F2 is assigned to a global variable, which causes F2 to always be in memory, and f2’s existence depends on F1, so F1 is always in memory and not collected by garbage collection when the call ends.

  1. By protecting the security implementation of variable JS private property and private methods (cannot be accessed by external) recommended reading: javascript.crockford.com/private.htm… Private properties and methods are not accessible outside of Constructor
function Constructor(...) {
    var that = this;
    var membername = value;
    function membername(...) {...}
}
Copy the code

Disadvantages of closures

  • Closures are not required for some specific task, and it is unwise to create functions in other functions because closures store variables in memory, negatively affecting script performance in terms of processing speed and memory consumption, and can lead to memory leaks in IE. The solution is to remove all unused local variables before exiting the function.
  • Closures change the values of variables inside the parent function, outside the parent function. So, if you use a parent function as an object, a closure as its Public Method, and internal variables as its private values, be careful not to arbitrarily change the values of the parent function’s internal variables.

For example, when creating a new object or class, methods should usually be associated with the object’s prototype rather than defined in the object’s constructor. The reason is that this causes the method to be reassigned each time the constructor is called (that is, for each object created, the method is reassigned).

function MyObject(name, message) {
  this.name = name.toString();
  this.message = message.toString();
  this.getName = function() {
    return this.name;
  };

  this.getMessage = function() {
    return this.message;
  };
}
Copy the code

In the above code, we did not take advantage of closures, so we can avoid using closures. Change it to the following:

function MyObject(name, message) { this.name = name.toString(); this.message = message.toString(); } MyObject.prototype = { getName: function() { return this.name; }, getMessage: function() { return this.message; }};Copy the code

But we don’t recommend redefining the prototype. Can be changed to the following example:

function MyObject(name, message) {
  this.name = name.toString();
  this.message = message.toString();
}
MyObject.prototype.getName = function() {
  return this.name;
};
MyObject.prototype.getMessage = function() {
  return this.message;
};
Copy the code

References:

  1. MDN
  2. JavaScript you Don’t Know (Volume 1)
  3. wikipedia
  4. Web.archive.org/web/2010082…
  5. www.cnblogs.com/cxying93/p/…