一、什么是閉包? 有什么作用
1.變量的作用域
??要理解閉包,首先必須理解JavaScript的變量作用域嘲碧。變量的作用域無非就是兩種:全局變量和局部變量稻励。在JavaScript中函數(shù)可以直接讀取外部的全局變量。
var a="你好";
function fun1(){
alert(a);
}
fun1();//輸出"你好"
另一方面在函數(shù)外部,無法讀取函數(shù)內(nèi)部的變量愈涩。
function fun2(){
var a="你好";
}
alert(a);//瀏覽器提示錯誤,VM55:4 Uncaught ReferenceError: a is not defined(…)
這里有一個問題需要注意,函數(shù)內(nèi)部聲明變量的時候,一定要使用var聲明,如果不使用var聲明,實(shí)際上是一個全局變量望抽。
function fun2(){
a="你好";
}
fun2();
alert(a);//"你好"
2.如何從外部讀取局部變量
??當(dāng)我們需要獲取到函數(shù)內(nèi)部的變量的時候,我們就需要在函數(shù)的內(nèi)部在定義一個函數(shù)。
function fun1(){
var a="你好";
function fun2(){
alert(a);//"你好"
}
return fun2();
}
fun1();
在上面的代碼中履婉,函數(shù)fun2就被包括在函數(shù)fun1內(nèi)部煤篙,這時fun1內(nèi)部的所有局部變量,對fun2都是可見的谐鼎。但是反過來就不行舰蟆,fun2內(nèi)部的局部變量趣惠,對fun1就是不可見的。這就是Javascript語言特有的"作用域鏈"結(jié)構(gòu)(chain scope)身害,子對象會一級一級地向上尋找所有父對象的變量味悄。所以,父對象的所有變量塌鸯,對子對象都是可見的侍瑟,反之則不成立。
??既然fun2可以讀取fun1中的局部變量,那么只要把fun2做為返回值就可以獲取到fun1中的變量了丙猬。那么函數(shù)fun2就可以成為閉包了涨颜。
3.閉包的概念
??由于在Javascript中,只有函數(shù)內(nèi)部的子函數(shù)才能讀取局部變量茧球,因此可以把閉包簡單理解成"定義在一個函數(shù)內(nèi)部的函數(shù)"庭瑰。所以,在本質(zhì)上抢埋,閉包就是將函數(shù)內(nèi)部和函數(shù)外部連接起來的一座橋梁弹灭。
4.閉包的作用
??閉包可以用在許多地方。它的最大用處有兩個揪垄,一個是前面提到的可以讀取函數(shù)內(nèi)部的變量穷吮,另一個就是讓這些變量的值始終保持在內(nèi)存中。
5.使用閉包的注意事項(xiàng)
??由于閉包會使得函數(shù)中的變量都被保存在內(nèi)存中饥努,內(nèi)存消耗很大捡鱼,所以不能濫用閉包,否則會造成網(wǎng)頁的性能問題酷愧,在IE中可能導(dǎo)致內(nèi)存泄露驾诈。解決方法是,在退出函數(shù)之前伟墙,將不使用的局部變量全部刪除翘鸭。
二滴铅、setTimeout 0 有什么作用
1.setTimeout() 方法用于在指定的毫秒數(shù)后調(diào)用函數(shù)或計(jì)算表達(dá)式戳葵。
2.setTimeout(f,0)的作用就是為了把f放到運(yùn)行隊(duì)列的最后去執(zhí)行。也就是說汉匙,無論setTimeout(f,0)寫在哪拱烁,當(dāng)之前的函數(shù)執(zhí)行完之后,f可以在最后立即執(zhí)行。
如上圖代碼所示,當(dāng)1和3輸出之后,立即執(zhí)行的是2噩翠。
三戏自、下面的代碼輸出多少?修改代碼讓fnArr [i] () 輸出 i伤锚。使用兩種以上的方法
var fnArr = [];
for (var i = 0; i < 10; i ++) {
fnArr[i] = function(){
return i;
};
}
console.log( fnArr[3]() ); //
1.輸出的結(jié)果為10
??我們可以先分析一下為什么輸出的結(jié)果為10:
??如上圖所示,for循環(huán)內(nèi)的函數(shù)可以寫成下面一種形式,因?yàn)閞eturn返回的是遍歷數(shù)組后的最后一個值10,所以最后的結(jié)果都是10擅笔。
2.方法一:賦值給立即執(zhí)行函數(shù),外部需要傳遞參數(shù)。
3.方法二:賦值給立即執(zhí)行函數(shù)猛们,聲明一個臨時變量存儲i的值念脯,外部不需要傳參。
4.方法三:把它綁定在函數(shù)上弯淘,作為函數(shù)的一部分绿店,不需要通過閉包,得到函數(shù)就能得到值庐橙。
四假勿、使用閉包封裝一個汽車對象,可以通過如下方式獲取汽車狀態(tài)
var Car = //todo;
Car.setSpeed(30);
Car.getSpeed(); //30
Car.accelerate();
Car.getSpeed(); //40;
Car.decelerate();
Car.decelerate();
Car.getSpeed(); //20
Car.getStatus(); // 'running';
Car.decelerate();
Car.decelerate();
Car.getStatus(); //'stop';
//Car.speed; //error
五态鳖、寫一個函數(shù)使用setTimeout模擬setInterval的功能
1.setTimeout為延時性定時器,可以設(shè)置多長時間之后執(zhí)行代碼(只執(zhí)行一次)转培。
2.setInterval為間隔性定時器,可以設(shè)置每隔多久執(zhí)行一次代碼(執(zhí)行多次)浆竭。
六堡距、寫一個函數(shù),計(jì)算setTimeout平均[備注:新加]最小時間粒度
七兆蕉、下面這段代碼輸出結(jié)果是? 為什么?
var a = 1;
setTimeout(function(){
a = 2;
console.log(a);
}, 0);
var a ;console.log(a);
a = 3;
console.log(a);
八羽戒、下面這段代碼輸出結(jié)果是? 為什么?
var flag = true;
setTimeout(function(){
flag = false;
},0)
while(flag){}
console.log(flag);
原因:以上代碼沒有輸出,因?yàn)閟etTimeout(f,0)會讓其包含的代碼在其它代碼執(zhí)行完后才能執(zhí)行虎韵;當(dāng)執(zhí)行完第一行代碼后直接跳到while語句易稠,而while語句中的判斷條件為真,將會一直執(zhí)行包蓝,進(jìn)入死循環(huán)驶社,所有沒有輸出。
九测萎、下面這段代碼輸出亡电?如何輸出delayer: 0, delayer:1...(使用閉包來實(shí)現(xiàn))
for(var i=0;i<5;i++){
setTimeout(function(){
console.log('delayer:' + i );
}, 0);
console.log(i);
}
1.方法一:利用函數(shù)f()嵌套,形成閉包,輸出delayer+i的值。
2.方法二: