1.什么是閉包? 有什么作用
- 閉包指有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域的變量的函數(shù)囊陡。創(chuàng)建閉包的常見(jiàn)方式 是 在一個(gè)函數(shù)內(nèi)部創(chuàng)建另一個(gè)函數(shù),并可以將一個(gè)函數(shù)返回掀亥。
- 官方對(duì)閉包的解釋是:一個(gè)擁有許多變量和綁定了這些變量的環(huán)境的表達(dá)式(通常是一個(gè)函數(shù))撞反,因而這些變量也是該表達(dá)式的一部分。閉包的特點(diǎn):
- 作為一個(gè)函數(shù)變量的一個(gè)引用搪花,當(dāng)函數(shù)返回時(shí)遏片,其處于激活狀態(tài)。
- 一個(gè)閉包就是當(dāng)一個(gè)函數(shù)返回時(shí)鳍侣,一個(gè)沒(méi)有釋放資源的棧區(qū)丁稀。簡(jiǎn)單的說(shuō)script允許使用內(nèi)部函數(shù)---即函數(shù)定義和函數(shù)表達(dá)式位于另一個(gè)函數(shù)的函數(shù)體內(nèi)。而且倚聚,這些內(nèi)部函數(shù)可以訪問(wèn)它們所在的外部函數(shù)中聲明的所有局部變量、參數(shù)和聲明的其他內(nèi)部函數(shù)凿可。當(dāng)其中一個(gè)這樣的內(nèi)部函數(shù)在包含它們的外部函數(shù)之外被調(diào)用時(shí)惑折,就會(huì)形成閉包。
- 在我的理解看來(lái)枯跑,閉包的作用是可以操作一個(gè)函數(shù)的局部變量惨驶。而阮一峰的解釋是閉包可以用在許多地方。它的最大用處有兩個(gè)敛助,一個(gè)是前面提到的可以讀取函數(shù)內(nèi)部的變量粗卜,另一個(gè)就是讓這些變量的值始終保持在內(nèi)存中。
可以看demo來(lái)理解:
//沒(méi)有使用閉包
for(var i =0; i<5; i++){
setTimeout(function(){
console.log('a'+i)
},0)
}
這個(gè)函數(shù)輸出的結(jié)果并不是想象的a0,a1,a2,a3,a4,而是5個(gè)a4纳击,這是因?yàn)樗鼒?zhí)行函數(shù)時(shí)续扔,i在函數(shù)里面并沒(méi)有聲明攻臀,因此他向外尋找刨啸,而i到4的時(shí)候停止循環(huán)识脆,因此尋找到i=4,所以离例,這就是得出5個(gè)a4的原因悉稠。
那么,我們可以使用閉包避免這個(gè)問(wèn)題洒扎,如下
for(var i=0;i<5;i++){
(function (num){
setTimeout(function(){
console.log('a'+num)
},0)
})(i);
}
原因是:它構(gòu)建一個(gè)只有自己本身才可訪問(wèn)的閉包袍冷,保存只供本身使用的變量(在我理解就是猫牡,在閉包里面處理各種變量淌友。)
參考:
阮一峰學(xué)習(xí)Javascript閉包(Closure)
2.setTimeout () 有什么作用
- 起到一個(gè)倒計(jì)時(shí)運(yùn)行的作用,時(shí)間設(shè)置為多少瑰抵,他就延遲多少時(shí)間運(yùn)行二汛,倘若是0就立即執(zhí)行
- 將setTimeout()里面的代碼放置代碼的最后運(yùn)行
var a=1;
setTimeout(function(){
console.log('before',a);
a = 2;
console.log('after',a);
},0);
a=100;
console.log(a);
//得出的結(jié)果先是 100
before 100
after 2
代碼
1.下面的代碼輸出多少拨拓?修改代碼讓fnArri輸出 i。使用兩種以上的方法
var fnArr = [];
for(var i=0; i<10; i++){
fnArr[i] = function(){
return i;
};
}
console.log(fnArr[3]()); //10
思路:可以用閉包讓fnArri輸出i
- 方法一:
var fnArr=[];
for(var i=0;i<10;i++){
fnArr[i] = (function(num){
return function(){
return num
};
})(i);
}
console.log(fnArr[3]());
- 方法二:
var fnArr=[];
for(var i=0;i<10;i++){
(function(){
var num = i;
fnArr[i] = function(){
return num;
}
})()
}
2.使用閉包封裝一個(gè)汽車對(duì)象婿着,可以通過(guò)如下方式獲取汽車狀態(tài)
var car =(function(){
var i =0;
function setSpeed(k){
i =k;
}
function getSpeed(){
return i;
}
function accelerate(){
i=i+10;
}
function decelerate(){
i=i-10;
}
function getStatus(){
if(i>0){
return 'running';
}
else
{
return 'stop';
}
}
return {
getSpeed:getSpeed,
setSpeed:setSpeed,
accelerate:accelerate,
decelerate: decelerate,
getStatus: getStatus
}
})();
Car.setSpeed(30);
console.log(Car.getSpeed());//30
Car.accelerate();
console.log(Car.getSpeed());//40;
Car.decelerate();
Car.decelerate();
console.log(Car.getSpeed()); //20
console.log(Car.getStatus()); // 'running';
Car.decelerate();
Car.decelerate();
console.log(Car.getStatus()); //'stop';
- 寫(xiě)一個(gè)函數(shù)使用setTimeout模擬setInterval的功能
var i =0;
function setInterval(){
setTimeout(function(){
console.log(i++)
setInterval())
},1000)
setInterval();
4.寫(xiě)一個(gè)函數(shù)提完,計(jì)算setTimeout平均[備注:新加]最小時(shí)間粒度
function getMini(){
var i =0;
var start = Date.now();
var clock = setTimeout(function(){
i++;
if(i === 1000){
clearTimeout(clock);
var end = Date.now();
console.log((start-end) / i) )
}
clock = setTimeout(arguments.callee,0)
},0)
5.下面這段代碼輸出結(jié)果是? 為什么?
var a = 1;
setTimeout(function(){
a = 2;
console.log(a); //2
}, 0);
var a ;console.log(a); //1
a = 3;console.log(a); //3
//但是console.log的順序是 1,3,2
//這是因?yàn)閟etTimeout會(huì)讓代碼放到代碼最后執(zhí)行
6.下面這段代碼輸出結(jié)果是? 為什么?
var flag = true;
setTimeout(function(){
flag = false;
},0)
while(flag){}
console.log(flag);
//這里并沒(méi)有輸出結(jié)果氯葬,因?yàn)閣hile(flag)會(huì)一直判斷是true帚称,這就會(huì)一直執(zhí)行循環(huán)秽澳,因此下面的代碼并不會(huì)執(zhí)行
7.下面這段代碼輸出担神?如何輸出delayer: 0, delayer:1...(使用閉包來(lái)實(shí)現(xiàn))
for(var i=0;i<5;i++){
setTimeout(function(){
console.log('delayer:' + i );//delayer5
}, 0);
console.log(i);} //5
for(var i=0;i<5;i++){
(function(num){
setTimeout(function(){
console.log('delayer:'+num);
},0)
})(i);
console.log(i);
}