函數(shù)的類型:
以上的幾種方法創(chuàng)建的函數(shù),除了匿名函數(shù)外祷杈,其他的都屬于普通函數(shù)斑司,但是JS還有幾種特殊的的函數(shù)類型
回調(diào)函數(shù):
將函數(shù)當做實參傳到另一個函數(shù)中,在另一個函數(shù)內(nèi)部調(diào)用但汞,稱為回調(diào)函數(shù)陡厘。
//創(chuàng)建一個函數(shù),并設置型參callbakc用來接收函數(shù)
function fun(callback){
//在函數(shù)內(nèi)部調(diào)用接收到的函數(shù)
callback();
}
//調(diào)用個函數(shù)特占,并傳入另一個函數(shù),且不限制類型云茸,可以是匿名函數(shù)
fun(function (){
console.log("我是回調(diào)函數(shù)");
});
既然傳入的實參也是函數(shù)是目,那么它也遵守函數(shù)的一切原則,且擁有函數(shù)的一切功能标捺,同樣可以傳入實參:
//設置一個函數(shù)懊纳,并設置三個型參用來接收回調(diào)函數(shù)和其他的兩個參數(shù)
function fn(myName,sex,callback){
//調(diào)用傳入的函數(shù),并設置兩個實參亡容,將設置的型參作為實參傳進去嗤疯,
callback(myName,sex);
}
//調(diào)用函數(shù),并設置實參闺兢,其中有將一個匿名函數(shù)作為實參傳入
fn('小蘭','女',function(myName,sex){
//傳入的其他兩個實參會傳給fn的型參然后作為實參傳入匿名函數(shù)
console.log('你好茂缚,我是' + myName + ',性別:' + sex)
});
注意: 函數(shù)和變量一樣,都擁有聲明提前的特性脚囊,所以調(diào)用不管是寫在前面還是寫在后面都管用
遞歸函數(shù):
函數(shù)內(nèi)部不斷的調(diào)用本身龟糕,以達到循環(huán)效果
function fun(num){
if(num<=1){
return 1;
}else{
return num * fun( --num );
//如果num大于1那么它將在它內(nèi)部再調(diào)用一次它自身
}
}
console.log( fun(3) );
以上的代碼的執(zhí)行過程相當于:
function fun(3){
if(num<=1){
return 1;
}else{
return 3 * function fun(2){
if(num<=1){
return 1;
}else{
return 2 * function fun(1){
if(num<=1){
return 1;
//num小于或等于1,返回1
}else{
return 2 * fun( --num );
}
};
//如果num大于1那么它將在它內(nèi)部再調(diào)用一次它自身
}
};
//如果num大于1那么它將在它內(nèi)部再調(diào)用一次它自身
}
}
console.log( fun(3) );
遞歸函數(shù)在調(diào)用自身的時候相當于是數(shù)個函數(shù)的嵌套悔耘,JS執(zhí)行代碼的過程是逐行執(zhí)行讲岁,執(zhí)行遞歸函數(shù)時同樣,一段代碼相當于從最里面開始向外一層一層的執(zhí)行的函數(shù)的集合衬以,所以千萬不要被調(diào)用自身的那一小段代碼迷惑:
function fun(num){
console.log(num);
if(num<1){
console.log("------");
}else{
fun(num-1);//當num不小于1的時候缓艳,調(diào)用自身,
};
console.log(num);
};
//相當于嵌套多個函數(shù)看峻,每個函數(shù)內(nèi)都有console.log(num);
fun(2);
//得到的結(jié)果是2 1 0 ------ 0 1 2
閉包函數(shù):
可以將函數(shù)內(nèi)部的變量返回到外部阶淘,在外部訪問
作用域
說到閉包,就不得不說一下作用域备籽,JS中的作用于有局部作用域個全局作用域:
- 在函數(shù)外聲明的變量為全局作用域舶治,任何函數(shù)的任何層嵌套都可以訪問,
- 在函數(shù)內(nèi)聲明的變量為局部作用域车猬,只有在函數(shù)內(nèi)和本函數(shù)嵌套的任意層函數(shù)可以訪問霉猛,
- 簡單來說,就是局部可以訪問全局珠闰,而全局不能訪問局部
var a = "我是全局變量";
function fun() {
var b = "我是局部變量";
console.log("我可以訪問"+a+"也可以訪問"+b+"O场!伏嗜!");
}
fun();
console.log("我可以訪問"+a+"但我訪問不了"+b+"L诚ぁ!承绸!");
//函數(shù)內(nèi)的代碼會被正常執(zhí)行裸影,但是函數(shù)外的代碼會報錯,找不到變量b
閉包函數(shù)
是通過return
給函數(shù)內(nèi)嵌套的函數(shù)內(nèi)定義一個變量军熏,然后將其返回出來轩猩,直到返回到需要的層域或全局:
function fun(){
return function(){
//將這個函數(shù)返回給上層函數(shù)
var a = 10;
return a;
//將變量a返回給函數(shù)
}
}
console.log(fun()());
閉包在JS中還有很多應用,也有很多的坑荡澎,這里先簡單了解一下
立即執(zhí)行函數(shù):
立即執(zhí)行函數(shù)也是匿名函數(shù)均践,但它和普通匿名函數(shù)所不同的是:匿名函數(shù)無法調(diào)用,而立即執(zhí)行函數(shù)是調(diào)用自身且只可調(diào)用一次摩幔,如下:
//普通匿名函數(shù)
function (){
console.log("我不能執(zhí)行彤委,因為我無法調(diào)用")
};
//立即執(zhí)行函數(shù)
;(function (){
console.log("我是立即執(zhí)行函數(shù),我調(diào)用我自己")
})();
//因為瀏覽器的原因或衡,最好在函數(shù)前后各加一個分號焦影,才不會因為某些原因出錯
你發(fā)現(xiàn)這兩者的區(qū)別了沒车遂?沒錯,其實就是在函數(shù)后加上了一個括號偷办,它的形式其實和其他類型的函數(shù)是一樣的
//定義一個函數(shù)
function myfun(){
}
//調(diào)用一個函數(shù)
myfun()艰额;
//myfun() == function myfun(){ }
因為瀏覽器會自動給代碼添加分號,為了讓瀏覽器認為匿名函數(shù)是一個整體椒涯,我們就需要用括號將整個函數(shù)包裹起來柄沮,然后在后面添加括號來調(diào)用,原理等同普通函數(shù)通過函數(shù)名調(diào)用废岂,
注意: 在代碼后需要添加分號結(jié)尾祖搓,為了防止前面因為漏加分號導致報錯,所以最好在代碼前也加上一個分號湖苞。