9 минут, понять закрытие

JavaScript

Замыкания — одна из трех гор JS, очень неприятная тема для многих фронтенд-разработчиков. Эта статья займет около 9 минут, чтобы сравнить и понять замыкания с 4 наборами очень простых примеров, которые могут изменить ваше прежнее понимание замыканий.

Прежде чем сравнивать случай, позвольте мне высказать свое мнение:Закрытия - это просто явление. Здесь мы не должны пытаться использовать официальное определение, чтобы понять значение замыкания бессловесным способом, что приведет к недопониманию. Наша цель — выяснить условия, при которых происходит явление замыкания при выполнении функции. Итак, давайте использовать 4 группы (всего 9 демонстраций, вы можете читать по одной в минуту) кейс-анализа, если вы можете понять, как происходит явление замыкания после прочтения, то все готово.

Первая группа, используйте ссылки на глобальные переменные для выполнения

var m, n;//全局变量

function outer_a1() {
	var num = 10;
	function inner() {
		console.log(num) //打印了outer_a1中定义的num
		debugger
	}
	m = inner;
}
outer_a1();
m();

function outer_a2() {
	var num = 10;
	function inner() {
		console.log("just console") //只做了简单的打印
		debugger
	}
	n = inner;
}
outer_a2();
n();

Приведенные выше два изображения являются снимками экрана консоли Chrome, когда выполняются external_a1() и external_a2() соответственно, а затем выполняются m() и n().После достижения точки останова отладчика мы видим, что появляется первый из них Closure And включает переменную num:10, вторая картинка не появляется Closure. Без объяснения продолжайте вторую группу сравнений случаев.

Вторая группа, внутренние прямого исполнения

function outer_b1() {
	var num = 15;
	function inner() {
		console.log(num) //打印了outer_b1中定义的num
		debugger
	}
	inner()
}
outer_b1();

function outer_b2() {
	var num = 15;
	function inner() {
		console.log("just console") //只做了简单的打印
		debugger
	}
	inner()
}
outer_b2();

Вторая группа похожа на первую группу, за исключением того, что inner выполняется непосредственно в external_b1 и external_b2.Мы можем обнаружить, что Closure первым генерирует переменную num: 15 (Примечание: если var num = 15; помещается во inner После выполнения () по правилу продвижения переменных значение переменной num в Замыкании не определено), при этом второй не генерирует Замыкание, а третья группа продолжает:

Третья группа, вернитесь и затем выполните

function outer_c1(s) {
	var num = 20;
	function inner() {
		console.log(s + num) //打印包含了outer_c1形参s和定义的num
		debugger
	}
	return inner
}
outer_c1()();

function outer_c2(s) {
	var num = 20;
	function inner() {
		console.log("just console") //只做了简单的打印
		debugger
	}
	return inner
}
outer_c2()();

Третья группа использовала return для возврата внутреннего внутреннего, а затем выполнила external_c1()() и external_c2()() соответственно для запуска внутреннего внутреннего и обнаружила, что первый сгенерировал замыкание, а второй — нет. первый формальный параметр s, который ссылается на external_c1, поэтому переменная в Closure также имеет дополнительный s, но фактический параметр не передается при выполнении external_c1(), поэтому значение s не определено.

Эти три группы случаев на самом деле очень похожи.Единственная разница между двумя демонстрациями в каждой группе заключается в том, что первая демонстрация печатает частные локальные переменные, принадлежащие внешней функции, а вторая демонстрация просто выполняет простую печать. На этом этапе можно приблизительно определить, что генерация замыкания не особо связана с методом выполнения, а определяется тем, ссылается ли внутренняя функция на приватные переменные внешней функции. Затем посмотрите на последнюю группу:

Группа 4, несколько способов вместе

var x, y, z; //全局变量

function outer_d1(s) {
	var num = 25;
	function inner1() {
		console.log(s) //打印形参s
		debugger
	}
	y = inner1;
	function inner2() {
		console.log("just console") //只做了简单的打印
		debugger
	}
	inner2();
	function inner3() {
		console.log(num) //打印定义的num
		debugger
	}
	return inner3
}
outer_d1("i am x");

function outer_d2(s) {
	var num = 25;
	function inner1() {
		console.log(s) //打印形参s
		debugger
	}
	
	function inner2() {
		console.log("just console") //只做了简单的打印
		debugger
	}

	function inner3() {
		console.log(num) //打印定义的num
		debugger
	}
	
	inner2();
}
outer_d2("i am y");

function outer_d3(s) {
	var num = 30;
	function inner1() {
		console.log("just console") //只做了简单的打印
		debugger
	}
	z = inner1;
	function inner2() {
		console.log("just console") //只做了简单的打印
		debugger
	}
	inner2();
	function inner3() {
		console.log("just console") //只做了简单的打印
		debugger
	}
	return inner3
}
outer_d3("i am z")();
z();

Эта группа сравнивает три примера.Первая группа и вторая группа немного отличаются.В первой группе в конечном итоге выполняются все внутренние функции, а во второй группе выполняется только одна внутренняя2,. Результат запуска не будет отображаться, вы можете запустить его самостоятельно, и вы обнаружите следующее явление:

  • 1. При переходе к каждому внутреннему элементу external_d1 будет Closure, а переменные Closure — num и s;
  • 2. При запуске к inner2 внутри external_d2 тоже будет Closure, а переменные Closure тоже num и s;
  • 3. Нет Замыкания при переходе к каждому внутреннему внутреннему внешнему_d3.

Несложно понять, что external_d3 не генерирует замыканий, потому что внутренние функции просто печатаются, но почему inner2 внутри external_d1 и external_d2 тоже просто печатаются, а замыкания тоже генерируются в процессе выполнения?

Это связано с тем, что их внутренние inner1 и inner3 относятся к закрытым переменным внешнего.В настоящее время external_d1 и external_d2 стали замыканием, поэтому, даже если inner2 ничего не печатает, оно уже находится в этой среде замыкания.Выполнить, когда сгенерированный Clouser Также видно, что переменные в сформированном Clouser являются локальными частными переменными внешнего, на которые ссылаются все внутренние функции.

Суммировать

По приведенным выше четырем наборам сравнительных случаев можно сделать вывод, что замыкание - это явление, порожденное выполнением функций при определенных обстоятельствах.Условиями этого явления являются:Когда функция (внешняя) выполняется, на ее формальные параметры или частные переменные (число, s) ссылается внутренняя функция (внутренняя).. Когда это условие выполняется, то этовнешний сформирует замыкание, переменные, содержащиеся в этом замыкании, — это все формальные параметры и локальные переменные, на которые ссылается внутренняя функция, когда работает сама внешняя. Это не имеет ничего общего с тем, возвращается внутренняя функция или нет, выполняется или не выполняется.