1. 程式人生 > >淺談對js閉包的理解

淺談對js閉包的理解

閉包就是能夠讀取其他函式內部變數的函式。由於在javascript中,只有函式內部的子函式才能讀取區域性變數,所以閉包可以理解成“定義在一個函式內部的函式“。在本質上,閉包是將函式內部和函式外部連線起來的橋樑。(引用了自由變數的函式)

function f1(){
  var a=10;  
  var b=20;
  function f2(){  
	 console.log(a);  
  }
  f2();  
}
f1()  

即使跳出了創造自己本身的空間也依然能夠訪問得到父函式的詞法環境

function f1(){
  var a=10;
  var b=20;
  return function f2(){
 	console.log(b);
  }
}
var result=f1();
result();

並沒有使用父級函式的變數(詞法環境裡面的東西),不會產生閉包

function f1(){
  var m=10;
  function f2(){
	 console.log('111');
  }
  f2();
}
f1()

使用父級的父級的變數也會產生閉包(作用域鏈的關係)

function f1(){
  var m=10;
  function f2(){
    var n=20;
    function f3(){
	  console.log(m)
    }
    f3()
  }
f2()
}
f1()

閉包的本質實際就是Js支援函式裡面巢狀函式,和作用域鏈機制

閉包的優勢:
    1.減少全域性變數(閉包會捕獲自己需要使用的父級變數,儲存起來,函式執行完後並不會馬上銷燬)

function f(){
  var a=0;
  return function(){
	 a++;
	 alert(a);
  }
}
var result=f();
result();  //1
result();  //2
result();  //3
result();  //4
	

2.減少傳遞給函式的引數數量
    業務邏輯:base為基數,max為最大值(基數+...+最大值)

function calFactory(base){
  return function(max){
	var total=0;
	for(var i=base;i<=max;i++){
	  total=total+i;
	}
	  alert(total)
  }
}
var result=calFactory(0);
result(5);

3.封裝

(function(){
  var m=0;
  function getM(){
	return m;
  }
  function setM(val){
	m=val;
  }
  window.getM=getM;
  window.setM=setM;
})()
setM(12);
alert(getM());;

使用閉包的注意點:

1.對捕獲的變數只是引用,不是複製

function f(){
  var num=1;
  function g(){
    alert(num);
  }
  num++;
  g()
}
f();  //2

2.父級函式每呼叫一次會產生不同的閉包

function f(){
  var num=1;
  return function(){
    num++;
    alert(num);
  }
}
var result=f();
result();  //2
result();  //3
var result2=f();
result2();  //2

3.迴圈中的問題

//假設頁面存在3個div,此時點選div全部彈3,因為i是一個全域性變數
var oDiv=document.getElementsByTagName('div');
for(var i=0;i<oDiv.length;i++){
  oDiv[i].onclick=function(){
     alert(i);
  }
}
	
//通過閉包解決,匿名函式每呼叫一次就會產生一個詞法環境,3次即時呼叫,產生3個詞法環境
oDiv=document.getElementsByTagName('div');
  for(var i=0;i<oDiv.length;i++){
    oDiv[i].onclick=(function(g){
      return function(){
        alert(g)
      }
    })(i)
}