JavaScript入門-函式function(二)
遞回函式
- 什么是遞回函式?
遞回簡單理解就是,在函式體里,呼叫自己,
//我們在求一個10的階乘的時候,可能會這么做
//寫一個回圈
var total = 1
for(var i=10; i>=1; i++){
total *= i ;
}
這樣的for回圈簡單直接,,,大家都會寫
但是,我們可以寫一個函式,遞回呼叫
//遞回函式
function jiecheng( n ){
if ( 1===n) return 1
return n*jiecheng(n-1)
}
//呼叫遞回函式
var total = jiecheng(10)
ps:兩種不同的方法,雖然結果都相同,但是還是有區別的,遞回并沒有通過for回圈遍歷每一個數,而且代碼量變少了,看起來有點高大上,
- 其實,在遞回呼叫的時候,就是按照return的特定來執行的,因為return只有在遇到一個具體的值才會回傳給呼叫者,
- 然后,在呼叫的時候,會有一個'堆疊'的資料結構(先進后出,后進先出),存盤每一個呼叫的時狀態,直到遇到一個能夠有具體值的狀態,就逐層往上回傳給呼叫者,最終的值就是你想要的值,
遞回的缺點:
- 每次呼叫自己的時候,其實一直都是在占用著記憶體,占用資源較大,
閉包
- 什么是閉包?
我們先來回顧一下,在es5里,用var定義的變數,不管是在代碼塊里定義,還是在for回圈里的區域變數,我們都能夠訪問到這個變數,這就叫做全域變數,如果我們在一個函式里用var定義變數,就是一個區域變數了,只有內部可以使用,
//定義全域變數
var a =1;
//函式體定義變數
function fun(){
var b =1;
}
//代碼塊里定義變數
{
var c = 1
{
var d = 'rainbow'
}
}
//for函式里的變數
for( var i = 0 ; i<10 ;i++){
console.log(i)
}
console.log( a , c , d , i )//1 1 "rainbow" 10
console.log(b)//error
ps:上面代碼可以看出來,在JavaScript里,除了方法體內的變數未區域變數,其他的都是全域變數,那如果我們想要訪問函式里面的變數該怎么辦呢??
這個時候,我們就要用到閉包了,
- 在函式內自定義一個方法,回傳函式定義的區域變數,
- 呼叫的時候,我們先呼叫外層的函式,得到的是一個函式體,然后再一次呼叫,就能夠獲取到outer的內部成員的變數了,
function outer(){
var num = 10;
funtion inner(){
console.log(num)
}
return inner;
}
var fun = outer()
fun()//10
或者
function outer() {
var age = 20;
return function () {//匿名函式
return age;
}
}
var age1 = outer();
console.log(age1())//20
總結:閉包,就是在函式內部定義一個函式,把function里私有的屬性,通過這個內部函式回傳給了外面,
特點:
- 通過閉包可以讀取函式內部的變數
- 每一次呼叫最外層的方法,實際都是重新開辟一塊記憶體空間., 因為回傳的inner方法沒有關閉,一直占用著記憶體,我們可以手動關閉 outer = null
- 在outer里定義的變數,通過閉包獲取到的成員變數,其實都是靜態static變數,正如第2點所說,變數還是存在記憶體中,并沒有主動釋放,
閉包的缺點:
- 和遞回類似,一直占用著記憶體資源,可能導致記憶體泄漏,
可能我自己講的不夠全,大家看看大佬的文章
徹底理解閉包
https://www.cnblogs.com/itjeff/p/10106855.html
阮一峰老師的
http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html
回呼函式
回呼函式有個比較逼格的名字——句柄,我們只要知道有這么個官方的叫法就行,以后面試或者交流的時候,也不至于聽不懂這是啥東西,
簡單理解就是,把一個函式當作引數,那么這個函式就是回呼函式,
那為啥叫回呼呢?
那是因為你執行一個方法時候,還不能夠預期或者確定會有什么樣的結果,必須得再回過頭來呼叫這個函式(也就是傳的引數),得到具體的結果,
function fun(callback){
console.log(callback)
}
//把一個方法當作引數
function say (value) {
alert(value);
}
alert(say);
alert(say('hi js.'));
ps:回呼函式應用場景多用在使用 js 寫組件時,尤其是組件的事件很多都需要回呼函式的支持,
內置函式
其實,我們js的類別庫提供了很多的函式,比如經常用的console.log(),alert()等等,但是在還未學習面向物件之前,主要來了解兩個內置函式,定時器setTimeout和setInterval
//使用方法
setTimeout(callback,delay);
setInterval(callback,delay);
function callback(){
console.log('rainbow');
}
var delay = 1*1000;
//解釋一下
callback:定時器要執行的方法
delay:定時器執行方法的間隔,單位ms毫秒
setTimeout、setInterval區別
- setTimeout 只能執行一次,而setInterval一直執行,
那么如何停止定時器呢?
每個定時器都會回傳一個定時器id,這個id在執行緒池中存著,我們接收他的id,然后清除
//接收id
var id1 = setTimeout(callback,delay);
var id2 = setInterval(callback,delay);
//關閉定時器
clearTimeout(id1)
clearInterval(id2)
ps:
- 關閉定時器,clearTimeout或者clearInterval都可以關閉對方的id,因為他們共用一個定時器ID poor,
- delay這個引數,并不會很精確,因為這和時間片輪轉有關,要想了解更多,可以去學習一下作業系統,行程和執行緒是什么,
其實,學習定時器的時候,我們就應該了解一下,js里只有單執行緒,而且理論是沒有異步操作的,大家口中說的那是模擬異步,那么大家就需要了解一個叫做任務佇列的東西,
說到這里,我們就來說三個任務,其實還有很多的:
- 渲染佇列:比如瀏覽器的渲染,ie的hasLayout
- 事件佇列:比如點擊事件onclick
- 定時器佇列:一定會等主程式執行完畢后再執行
這些都是有一定執行順序的,渲染佇列->事件佇列->定時器佇列,所以定時器這個玩意,就像個棄兒,凡事都要最后才能擁有,這也就知道為啥你給他設定delay時間的時候,不會那么精確了,
謝謝大家能讀完這篇隨筆,鄙人學識淺薄,很多地方講的自認為不是很深入,也比較的俗,見諒見諒...
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/250117.html
標籤:其他
