匿名函數(shù)
創(chuàng)建匿名函數(shù)的情況一般是將匿名函數(shù)保存在一個變量里案训,或者將其作為一個對象的方法买置,或者將其作為一個回調(diào)。
// 匿名函數(shù)直接作為鼠鍵處理程序
window.onload=function (){console.log(1)};
// 匿名函數(shù)作為某個對象的一個方法
var a={
x: function () {
console.log(1)
}
};
a.x();
// 匿名函數(shù)作為回調(diào)函數(shù)傳遞給setTimeout()方法
setTimeout(function(){
console.log(1)
},500);
遞歸
遞歸函數(shù)有兩個條件:引用自身强霎,并且有終止條件忿项。遞歸函數(shù)不能終止于無限循環(huán)。
普通命名函數(shù)中的遞歸
// 在函數(shù)內(nèi)部通過調(diào)用函數(shù)自身,直到條件結(jié)束
function a(n){
return n>1?a(n-1)+1:1;
}
console.log(a.x(5)); // 5
作為方法中的遞歸
將一個遞歸函數(shù)作為一個對象的方法轩触,遞歸函數(shù)會變?yōu)橐粋€匿名函數(shù)賦值給對象的一個屬性寞酿。
// 通過引用對象的屬性名稱來調(diào)用該匿名函數(shù)進行遞歸
var a={
x:function (n){
return n>1? a.x(n-1)+1:1;
}
};
console.log(a.x(5)); // 5
這樣的引用方法存在引用丟失的問題,例如:
// 定義一個新對象b脱柱,該對象也引用之前a對象上的匿名遞歸函數(shù)伐弹。
var b={
x: a.x
};
//重新定義a對象,去除所有屬性榨为,此時a上的x屬性已經(jīng)沒有了
a={};
console.log(b.x(5)); // 報錯 在執(zhí)行遞歸函數(shù)時惨好,b中的x方法依然是使用a.x來調(diào)用自身,a.x已經(jīng)不存在随闺,所以報錯
在匿名函數(shù)中不再使用顯示的a引用日川,而是使用函數(shù)上下文(this)進行引用可以解決這一問題。
// 當(dāng)函數(shù)作為方法被調(diào)用時板壮,函數(shù)上下文指的是調(diào)用該方法的對象
var a={
x:function (n){
return n>1? this.x(n-1)+1:1;
}
};
// 調(diào)用b.x()方法時逗鸣,其中的this指向b
console.log(b.x(5)); // 5
還存在一個問題,這樣修改代碼后绰精,b對象引用a.x的方法名稱也必須為x,因為遞歸函數(shù)是使用this.x調(diào)用透葛,屬性名為x被固定死了笨使。給匿名遞歸函數(shù)取一個名稱,再通過該名稱調(diào)用僚害,可以解決這一問題硫椰,這樣的匿名遞歸函數(shù)被稱為內(nèi)聯(lián)函數(shù)(一個具有名稱的匿名函數(shù))。
// 給匿名函數(shù)命名萨蚕,再通過該名稱進行遞歸調(diào)用
var a={
x:function z(n){
return n>1? z(n-1)+1:1;
}
};
// b中原本的x屬性名可以修改為任意名稱靶草,再對a中的x方法進行引用
var b={
y: a.x
};
a={};
console.log(b.y(5)); // 5
內(nèi)聯(lián)函數(shù)還可以在賦值給變量的時候使用
var a= function b(){
console.log(b); // 可以訪問到名稱b
};
a();
console.log(b); // 報錯,b在函數(shù)外部不可以訪問到岳遥,證明內(nèi)聯(lián)函數(shù)聲明的名稱的作用域只在函數(shù)體內(nèi)部可訪問
還有一種通過arguments的callee屬性調(diào)用函數(shù)自身的方法奕翔,不過callee在新版的Javascript被去除。現(xiàn)版本的嚴(yán)格模式下也禁用了這一屬性浩蓉。arguments.callee引用的是當(dāng)前所執(zhí)行的函數(shù)本身派继。
var a={
x:function (n){
return n>1? arguments.callee(n-1)+1:1;
}
};
var b={
y: a.x
};
a={};
console.log(b.y(5)); // 5
可變長度的參數(shù)列表
使用apply()可以使函數(shù)的參數(shù)列表長度可變
// Javascript中查找最大或最小值時,參數(shù)需要一個一個傳入捻艳,無法直接傳入元素數(shù)量不定的數(shù)組驾窟。
var a= Math.max(1,2,3);
console.log(a); // 3
// 使用apply()調(diào)用函數(shù),第二個參數(shù)作為數(shù)組傳入
var a=[1,2,3];
var b=Math.max.apply(Math,a);
console.log(b); // 3
即使只定義了固定數(shù)量的形式參數(shù)认轨,仍然可以是用arguments參數(shù)列表訪問到所有的參數(shù)绅络,因為argument參數(shù)列表總是指向所有參數(shù)的集合。函數(shù)本身也具有l(wèi)ength屬性,與arguments屬性的length不同在于恩急,函數(shù)本身的length表示函數(shù)在定義的時候定義了幾個形式參數(shù)杉畜,而arguments的length屬性表示實際調(diào)用函數(shù)時傳入了幾個參數(shù)。利用這兩個length的差別可以在Javascript中實現(xiàn)函數(shù)的重載假栓。
// 定義一個方法寻行,將一系列匿名函數(shù)綁定在一個對象的同名屬性下,根據(jù)傳入?yún)?shù)數(shù)量的不同運行不同的匿名函數(shù)
function add(obj, name, fn) {
var old=obj[name];
obj[name]=function () {
if(fn.length===arguments.length){
return fn.apply(this,arguments);
}else if(typeof old==="function"){
return old.apply(this,arguments);
}
}
}
var a={};
add(a,"b",function () {
console.log(0);
});
add(a,"b",function (x) {
console.log(x);
});
add(a,"b",function (x,y) {
console.log(x+y);
});
// 傳入的參數(shù)數(shù)量不同匾荆,執(zhí)行的匿名函數(shù)也不同
a.b(); // 0
a.b(1); // 1
a.b(1,2); // 3
函數(shù)判斷
兼容各個瀏覽器的函數(shù)判斷方法:
function isFunction(fn){
return Object.prototype.toString.call(fn)==="[object Function]"
}