閉包——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,繼續第三組:閉包
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)運行時它的形參或者它的局部變量被其餘函數所引用。知足這個條件時,那麼這個outer就會造成閉包,這個閉包所包含的變量爲outer自己運行時被其餘函數引用到的全部形參和局部變量。形參和變量被引用的方式能夠是內部直接運行(包括自執行匿名函數)、被賦值給外部變量、或者是被return。debug