一、閉包的概念:指有權訪問另外一個函數做用域中的變量的函數,通常狀況就是在一個函數中包含另外一個函數。編程
二、閉包的做用:訪問函數內部變量、保持函數在環境中一直存在,不會被垃圾回收機制處理閉包
由於函數內部聲明 的變量是局部的,只能在函數內部訪問到,可是函數外部的變量是對函數內部可見的,這就是做用域鏈的特色了。dom
子級能夠向父級查找變量,逐級查找,找到爲止函數
1 function bar(){ 2 //外層函數聲明的變量 3 var value=1; 4 5 function foo(){ 6 console.log(value); 7 } 8 return foo(); 9 }; 10 var bar2=bar; 11 //實際上bar()函數並無由於執行完就被垃圾回收機制處理掉 12 //這就是閉包的做用,調用bar()函數,就會執行裏面的foo函數,foo這時就會訪問到外層的變量 13 bar2();
所以咱們能夠在函數內部再建立一個函數,這樣對內部的函數來講,外層函數的變量都是可見的,而後咱們就能夠訪問到他的變量了。spa
三、閉包的優勢:code
四、閉包的缺點:對象
由於使用閉包,能夠使函數在執行完後不被銷燬,保留在內存中,若是大量使用閉包就會形成內存泄露,內存消耗很大blog
1。在函數外使用函數內的變量 .函數做爲返回值 (閉包做用:避免變量被環境污染)ip
1 function F1(){ 2 var a = 100; 3 return function(){ 4 console.log(a) 5 } 6 } 7 var f1 =F1(); 8 var a = 200; 9 f1()//100
1 function init(){ 2 var name = "hello world";//name是一個被init建立的局部變量 3 function sayName(){//sayName是一個內部函數,閉包 4 alert(name);//使用了父級函數聲明的變量name 5 } 6 sayName(); 7 } 8 init();//"hello world"
2.函數做爲參數傳遞內存
1 function F1(){ 2 var a = 100; 3 return function(){ 4 console.log(a) 5 } 6 } 7 var f1 =F1(); 8 function F2(fn){ 9 var a = 200; 10 fn(); 11 } 12 F2(f1); // 100
3.將函數與其所操做的某些數據關聯起來,一般,你使用只有一個方法的對象的地方,均可以使用閉包
1 // 改變dom樣式 2 document.getElementById("a").onclick = setSize(12); 3 document.getElementById("b").onclick = setSize(18); 4 document.getElementById("c").onclick = setSize(22); 5 function setSize(fontSize){ 6 return function(){ 7 document.body.style.fontSize = fontSize + 'px'; 8 } 9 }
4.用閉包模擬私有方法
1 //這三個公共函數是共享同一個環境的閉包。多虧 JavaScript 的詞法做用域,它們均可以訪問 privateCounter 變量和 changeBy 函數。 2 var makeCounter = function () { 3 var privateCounter = 0; 4 function changeBy(val){ 5 privateCounter += val; 6 }; 7 return { 8 increment: function(){ 9 changeBy(1); 10 }, 11 decrement: function(){ 12 changeBy(-1); 13 }, 14 value: function(){ 15 return privateCounter; 16 } 17 } 18 }; 19 var Counter1 = makeCounter(); 20 var Counter2 = makeCounter(); 21 Counter1.increment(); 22 console.log(Counter1.value());//1 每次調用其中一個計數器時,經過改變這個變量的值,會改變這個閉包的詞法環境。然而在一個閉包內對變量的修改,不會影響到另一個閉包中的變量。 23 console.log(Counter2.value());//0 以這種方式使用閉包,提供了許多與面向對象編程相關的好處 —— 特別是數據隱藏和封裝。
5.循環裏面的閉包
怎麼才能實現輸出0-5呢?
1 for (var i = 0; i < 5; i++) { 2 setTimeout(function () { 3 console.log(i); 4 }, 1000 * i); 5 }//55555
//方法一,makeCallback函數爲每個回調建立一個新的詞法環境。 function makeCallback(i) { return function() { console.log(i) }; } for(var i=0;i<10;i++){ setTimeout(makeCallback(i),1000) }
//另外一種方法使用了匿名閉包 for(var i=0;i<10;i++){ (function(i){ setTimeout(function () { console.log(i) },1000) })(i) }
1 //使用let聲明變量 2 for (let i = 0; i < 5; i++) { 3 setTimeout(function () { 4 console.log(i); 5 }, 1000 * i); 6 }