JavaScript Basics – Closures
Understanding the concept of closures is important for learning JavaScript, many novice (including me) began to learn the closure, will feel indefinitely, before looking at some information, organized a closure of a blog, if there is negligence and error, I hope that we have a lot of advice.
Overview
Understanding the concept of closures, we recommend that you first recall the relevant knowledge of the JS scope, if you have questions about the classmate, you can refer to: JavaScript base – scope. Closures are defined as follows:
Closure is when a function was able to remember and access it lexical scope even when this function is executing outside I TS lexical scope.
The free translation is that when a function is executed outside its lexical scope, it can still access variables in its lexical scope. The "lexical scope" here is the scope that we generally understand.
Let's start with an example.
Eg1
function foo () { var a = 2; function Bar () { console.log (a); } Bar ();} Foo (); -2
In the above example, when the function is called bar()
, the a
value of the variable is taken from the scope of the function, that is, foo
bar()
the upper scope of the function, from the concept of closure, this example basically belongs to a closure. Why is it "basic", because it a
is actually a bar()
variable on the scope chain of a function, we call it a nested scope more. Let's look at one more example:
Eg2
function foo () { var a = 2; function Bar () { console.log (a); }
The EG2 example might be more likely to embody the concept of closures: when we define foo()
a function, we return a function, assign a reference to the var test = foo();
function test
, and then, when we execute the test();
statement, we find that a
the value is still available, and we call it bar()
a closure.
Closure principle: When the compiler executes var test = foo();
, it identifies it as a closure, and the garbage collector retains the scope chain of the closure when it reclaims memory. So test()
at runtime, you can access the lexical scopes defined by the closures.
function settimeout ()
In fact, when we write the JS code, we often use closures, but we do not realize that, for example setTimeout()
:
Eg3
function Wait (message) { setTimeout (function timer () { console.log (message); }, 1000);} Wait ("Hello, closure!");
I believe that the students have more or less used setTimeout()
, in the eg3 we pay careful attention, we can find that our definition in wait()
the anonymous function is deferred operation, but it can still access to the variable message
. The concept of the closure of the control, is not clear. Similarly, when we define many asynchronous functions, we use closures. is not found in the closure of the fact that we are always in use.
Closures in the loop
Let's start by looking at an example.
Eg4
for (var i=1; i<=5; i++) { setTimeout (function timer () { console.log (i); }, i*1000);}
What do you think will be entered in EG4? Is it 1,2,3,4,5? If you assign the code to the browser console panel, you may be disappointed that the code output is 6,6,6,6,6; Do many students think that each one i
is not running alone? How the output is all 6.
Before analyzing this example, we have a concept in mind: JS is applied to function scopes, not block-level scopes. Reflected in the EG4, is the circulation of the use of the i
public. So at the timer()
time of execution, i
it has become 6.
If JS Iife (execute function immediately) is applied, will the output be 5 6? Like what:
Eg5
for (var i=1; i<=5; i++) { (function () { setTimeout (function timer () { console.log (i); }, i*1000 ); }) ();}
We can test it, and the result is 6,6,6,6,6. Or does anyone think that if the delay time is shortened enough, the result will be normal? The actual results may disappoint you. Even if we set the delay time to 0, the result is the same, because the for
execution efficiency is inherently setTimeout()
higher, and setTimeout()
how to shorten the delay time for
.
In order to achieve our desired results, the solution is to bring each loop into i
time()
the scope, such as:
Eg6
for (var i=1; i<=5; i++) { (function () { var j = i; SetTimeout (function timer () { console.log (j); }, j*1000); }) ();}
Or is:
Eg7
for (var i=1; i<=5; i++) { (function (j) { setTimeout (function timer () { console.log (j); }, j* ); }) (i);}
extension : The introduction let
of keywords in ES6, and the purpose is to implement block-level scope in JS, so the code in EG5 can also be modified to:
Eg8
for (var i=1; i<=5; i++) {let j = i; SetTimeout (function timer () { console.log (j); }, j*1000);}
Or
Eg9
for (let I=1; i<=5; i++) { setTimeout (function timer () { console.log (i); }, i*1000);}
Closure Applications – modules (module)
Modules are typical examples of application closures, let's look at an example:
Eg10
function Coolmodule () { var something = "cool"; var another = [1, 2, 3]; function dosomething () { console.log (something); } function Doanother () { Console.log ("Another.join ("! ")); } return { dosomething:dosomething, doanother:doanother };} var foo = coolmodule (); foo.dosomething (); Coolfoo.doanother (); 1! 2! 3
In Eg10 CoolModule
is a function that returns a value of one object, then a foo
closure is doSomething
doAnother
generated when called and. This is the module
simplest example of using closures, so let's look at an example of how to resolve module
dependencies.
Eg11
Defining the implementation of a dependent module
var mymodules = (function Manager () { var modules = {}; function define (name, Deps, Impl) {for (var i=0; i<deps.length; i++) { deps[i] = modules[deps[i]]; } Modules[name] = impl.apply (Impl, deps); } function get (name) { return modules[name]; } return { define:define, get:get };}) ();
Let's analyze the above code. First, an empty object is defined, and module
then the function is defined, with three parameters: defining the name of the module, defining the module's define
name
dependencies, deps
impl
and defining how the module is implemented.
Mymodules.define ("foo", ["bar"], function (bar) { var hungry = "Hippo"; function Awesome () { console.log (Bar.hello (Hungry). toUpperCase ()); } return { awesome:awesome };}); var bar = mymodules.get ("bar"), var foo = mymodules.get ("foo"), Console.log ( Bar.hello ("Hippo"));/Let me introd Uce:hippofoo.awesome (); Let ME Introduce:hippo
Of course ES6 also introduced the module, making the call more convenient, look directly at the example bar
Eg12
Bar.js
function Hello (WHO) { return ' let me introduce: ' + Who;} Export Hello;
Foo.js
Import only ' hello () ' from the ' bar ' Moduleimport Hello from "bar", var hungry = "Hippo"; function awesome () { consol E.log ( hello (hungry). toUpperCase () );} Export awesome;
Import the entire "foo" and "Bar" Modulesmodule foo from "foo", module bar from "Bar", Console.log ( Bar.hello ("Rhino " )); Let me Introduce:rhinofoo.awesome (); Let ME Introduce:hippo
Note There are two ways to call module in Eg12, respectively, import
and module
, the former is the interface, and the latter calls the module, the usage is slightly different, the former is the direct interface itself hello(hungry)
, and the latter is the method in the calling module bar.hello("rhino")
.
Reference documents
JavaScript Basics – Closures