原生的setTimeout傳遞的第一個函數不能帶參數,經過閉包能夠實現傳參效果bash
setTimeout(function(param){
alert(param)
},1000)
//經過閉包能夠實現傳參效果
function func(param){
return function(){
alert(param)
}
}
var f1 = func(1);
setTimeout(f1,1000);
複製代碼
咱們定義行爲,而後把它關聯到某個用戶事件上(點擊或者按鍵)。咱們的代碼一般會做爲一個回調(事件觸發時調用的函數)綁定到事件上閉包
<body>
<p>哈哈哈哈哈哈</p>
<h1>hhhhhhhhh</h1>
<h2>qqqqqqqqq</h2>
<a href="#" id="size-12">12</a>
<a href="#" id="size-14">14</a>
<a href="#" id="size-16">16</a>
<script>
function changeSize(size){
return function(){
document.body.style.fontSize = size + 'px';
};
}
var size12 = changeSize(12);
var size14 = changeSize(14);
var size16 = changeSize(16);
document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;
</script>
</body>
複製代碼
用閉包定義能訪問私有函數和私有變量的公有函數app
var counter = (function(){
var privateCounter = 0; //私有變量
function change(val){
privateCounter += val;
}
return {
increment:function(){ //三個閉包共享一個詞法環境
change(1);
},
decrement:function(){
change(-1);
},
value:function(){
return privateCounter;
}
};
})();
console.log(counter.value());//0
counter.increment();
counter.increment();//2
複製代碼
'use strict';
function create_counter(initial) {
var x = initial || 0;
return {
inc: function () {
x += 1;
return x;
}
}
}
複製代碼
運行結果:函數
var c1 = create_counter();
c1.inc(); // 1
c1.inc(); // 2
c1.inc(); // 3
var c2 = create_counter(10);
c2.inc(); // 11
c2.inc(); // 12
c2.inc(); // 13
複製代碼
在返回的對象中,實現了一個閉包,該閉包攜帶了局部變量x,而且,從外部代碼根本沒法訪問到變量x。換句話說, 閉包就是攜帶狀態的函數,而且它的狀態能夠徹底對外隱藏起來。ui
function count() {
var arr = [];
for (var i=1; i<=3; i++) {
arr.push(function () {
return i * i;
});
}
return arr;
}
var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];
複製代碼
在上面的例子中,每次循環,都建立了一個新的函數,而後,把建立的3個函數都添加到一個Array中返回了。spa
你可能認爲調用f1(),f2()和f3()結果應該是 1 4 9
, 但實際結果是:.net
f1(); // 16
f2(); // 16
f3(); // 16
複製代碼
所有都是16!緣由就在於返回的函數引用了變量i,但它並不是馬上執行。等到3個函數都返回時,它們所引用的變量i已經變成了4,所以最終結果爲16。code
返回閉包時牢記的一點就是:返回函數不要引用任何循環變量,或者後續會發生變化的變量。對象
若是必定要引用循環變量怎麼辦?方法是再建立一個函數,用該函數的參數綁定循環變量當前的值,不管該循環變量後續如何更改,已綁定到函數參數的值不變:blog
function count() {
var arr = [];
for (var i=1; i<=3; i++) {
arr.push((function (n) {
return function () {
return n * n;
}
})(i));
}
return arr;
}
var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];
f1(); // 1
f2(); // 4
f3(); // 9
複製代碼
注意這裏用了一個「建立一個匿名函數並馬上執行」的語法:
(function (x) {
return x * x;
})(3); // 9
複製代碼
有時候閉包會在你不經意的時候出現,你可能已經看到了咱們稱之爲局部應用程序的示例,以下面的代碼所示。
let c = 4
const addX = x => n => n + x
const addThree = addX(3)
let d = addThree(c)
console.log('example partial application', d)
複製代碼
若是不使用箭頭函數,等效的代碼以下:
let c = 4
function addX(x) {
return function(n) {
return n + x
}
}
const addThree = addX(3)
let d = addThree(c)
console.log('example partial application', d)
複製代碼
咱們聲明瞭一個通用加法函數 addX,它接受一個參數(x)並返回另外一個函數。
返回的函數也接受一個參數並將其與變量 x 相加。
變量 x 是閉包的一部分,當在本地上下文中聲明變量 addThree 時,它會分配到一個函數定義和一個閉包,閉包含變量 x。
因此,當調用並執行 addThree 時,它能夠從閉包中訪問變量 x 和變量 n(做爲參數傳遞進去),並返回相加的和。
在這個示例中,控制檯將打印數字 7。
參考文章連接: