Closures, one of the three big mountains of JS, are a headache for many front-end developers. This article will take about nine minutes to compare and contrast closures with four sets of very simple examples that may change your understanding of closures.

Before we compare the examples, let me give you an idea: closures are just a phenomenon. Here, we should not try to understand closures in terms of the official definition, as that would be a mistake. Our goal is to find the conditions under which closure occurs when a function executes. So let’s take four sets of cases (nine demos, one per minute), and if we can figure out how closures happen, we’re done.

The first group is executed with a global variable reference

var m, n;// Global variables

function outer_a1() {
	var num = 10;
	function inner() {
		console.log(num) Outer_a1 prints the num defined in outer_a1
		debugger
	}
	m = inner;
}
outer_a1();
m();

function outer_a2() {
	var num = 10;
	function inner() {
		console.log("just console") // Just a simple print
		debugger
	}
	n = inner;
}
outer_a2();
n();
Copy the code

Outer_a1 (); outer_a2(); outer_a2(); m(); n(); There is no Closure in the second diagram. Without explanation, let’s move on to the second set of cases.

The second group, internal direct execution

function outer_b1() {
	var num = 15;
	function inner() {
		console.log(num) Outer_b1 prints the num defined in outer_b1
		debugger
	}
	inner()
}
outer_b1();

function outer_b2() {
	var num = 15;
	function inner() {
		console.log("just console") // Just a simple print
		debugger
	}
	inner()
}
outer_b2();
Copy the code

Outer_b1 and outer_B2 create a Closure that contains the variable num:15(note: var num = 15; Closure (num = undefined) after inner(), and Closure (num = undefined) after inner()

The third group, return and then execute

function outer_c1(s) {
	var num = 20;
	function inner() {
		console.log(s + num) // Print contains the outer_c1 parameter s and num defined
		debugger
	}
	return inner
}
outer_c1()();

function outer_c2(s) {
	var num = 20;
	function inner() {
		console.log("just console") // Just a simple print
		debugger
	}
	return inner
}
outer_c2()();
Copy the code

Outer_c1 ()() and outer_c2()() to run the inner Closure, but the Closure is not present in the second group. Outer_c1 () is called without an argument, so s is undefined. The Closure argument is called without an outer_c1() argument.

All three sets of cases are actually very similar, with the only difference between the two demos in each set being that the first one prints a private local variable belonging to the outer function, while the second one simply prints. At this point, it’s pretty clear that closures are generated not specifically by how they are executed, but by whether the inner function references the private variables of the outer function. And then to the last group:

The fourth group, a variety of ways together

var x, y, z; // Global variables

function outer_d1(s) {
	var num = 25;
	function inner1() {
		console.log(s) // Prints parameter s
		debugger
	}
	y = inner1;
	function inner2() {
		console.log("just console") // Just a simple print
		debugger
	}
	inner2();
	function inner3() {
		console.log(num) // Prints the num defined
		debugger
	}
	return inner3
}
outer_d1("i am x");

function outer_d2(s) {
	var num = 25;
	function inner1() {
		console.log(s) // Prints parameter s
		debugger
	}
	
	function inner2() {
		console.log("just console") // Just a simple print
		debugger
	}

	function inner3() {
		console.log(num) // Prints the num defined
		debugger
	}
	
	inner2();
}
outer_d2("i am y");

function outer_d3(s) {
	var num = 30;
	function inner1() {
		console.log("just console") // Just a simple print
		debugger
	}
	z = inner1;
	function inner2() {
		console.log("just console") // Just a simple print
		debugger
	}
	inner2();
	function inner3() {
		console.log("just console") // Just a simple print
		debugger
	}
	return inner3
}
outer_d3("i am z") (); z();Copy the code

This group compares three examples. The first group is slightly different from the second. In the first group, all inner2 is executed, while in the second group, only one inner2 is executed. Run the results will not map, you can run your own, the results will find the following phenomenon:

  • The Closure variables are num and s, and the Closure variables are all closed when running to each inner in outer_d1.
  • The Closure variable is num and S, and the Closure variable is inner2 of the outer_d2.
  • 3. Run to each inner inside outer_d3 without Closure.

Outer_d3 does not generate a closure. It is understandable that the inner functions of the outer_d1 and outer_d2 simply print, but why does the inner2 function of the outer_d1 and outer_D2 simply print, but also generate a closure?

Outer_d1 and outer_d2 are now closures, so even though inner2 doesn’t print anything, it’s already inside the closure, and you’ll see the Clouser generated. The variables in the resulting Clouser are the local private variables that outer is referenced by all inner functions.

conclusion

From the above comparison of the four cases, we can conclude that closures are a phenomenon that occurs when a function (outer) is run and its parameters or private variables (num,s) are referenced by an inner function (inner). When this condition is met, the Outer will form a closure containing all the arguments and local variables referenced by the inner function when the Outer itself is run. It doesn’t matter if the inner function returns or doesn’t return, gets executed or doesn’t get executed.