9分鐘,搞明白閉包

閉包——JS三座大山之一,對不少前端開發者來講是個很是頭疼的知識點。本文將花費大約9分鐘時間,用4組很是簡單的例子來對比理解閉包。前端

在案例對比以前,先給你們一個觀點:閉包只是一種現象。咱們不要試圖用官方的定義,以扣字眼的方式去理解閉包的含義,若是看完下面的4組案例後,能搞清楚閉包這種現象是如何產生的,那就大功告成了。chrome

第一組、外部引用再執行

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();
複製代碼

上面兩張圖片是分別執行outer_a1()和outer_a2()後再執行m()和n()時,到其中的debugger斷點後,chrome控制檯的截圖,咱們能夠看出第一個出現了Closure幷包含了變量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();
複製代碼

第二組跟第一組差很少,只是改成了在outer_b1和outer_b2中直接執行了inner,咱們能夠發現仍是第一個產生了Closure包含變量num:15(備註:若是把var num = 15;放在inner()執行的後面,根據變量提高規則,Closure中的變量num值就是undefined),第二個並無產生Closure,繼續第三組:閉包

第三組、return後再執行

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把內部的inner返回出來,而後分別執行outer_c1()()和outer_c2()()來運行內部的inner,發現仍是第一個產生了Closure而第二個沒有Closure,不一樣的是第一個又引用了outer_c1的形參s,因此Closure中的變量也多了一個s,不過執行outer_c1()時並無傳入實參,因此s的值是undefined。再來看下最後一組吧:函數

第四組、多種方式一塊兒

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

function outer_d1(s) {
	var num = 25;
	function inner1() {
		console.log(num) //打印定義的num
		debugger
	}
	x = inner1;
	function inner2() {
		console.log("just console") //只作了簡單的打印
		debugger
	}
	inner2();
	function inner3() {
		console.log(num) //打印定義的num
		debugger
	}
	return inner3
}
outer_d1("i am x")();
x();

function outer_d2(s) {
	var num = 25;
	function inner1() {
		console.log(s) //打印outer_d2的形參s
		debugger
	}
	y = inner1;
	function inner2() {
		console.log("just console") //只作了簡單的打印
		debugger
	}
	inner2();
	function inner3() {
		console.log(num) //打印定義的num
		debugger
	}
	return inner3
}
outer_d2("i am y")();
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();
複製代碼

最後一組對比了三個例子就不上截圖了,就是上面三組一塊兒上,你們能夠本身運行下,結果會發現:spa

  • 一、運行到outer_d1和outer_d2內部的各個inner時都會有Closure,運行到outer_d3內部的各個inner時沒有Closure。
  • 二、運行到outer_d1內部的各個inner時產生的Closure的變量爲num,運行到outer_d2內部的各個inner時產生的Closure的變量爲num和s,s的值爲各自的實參數據。
  • 三、outer_d1和outer_d2內部的inner2雖然只是作了簡單的打印,可是也產生了Closure。

總結

閉包是函數在特定狀況下執行產生的一種現象,這種現象產生的條件爲:當一個函數(outer)運行時它的形參或者它的局部變量被其餘函數所引用。知足這個條件時,那麼這個outer就會造成閉包,這個閉包所包含的變量爲outer自己運行時被其餘函數引用到的全部形參和局部變量。形參和變量被引用的方式能夠是內部直接運行(包括自執行匿名函數)、被賦值給外部變量、或者是被return。debug

相關文章
相關標籤/搜索