1.函數(shù)作為返回值
高階函數(shù)不僅僅可以接受函數(shù)作為參數(shù),還可以把函數(shù)當(dāng)做結(jié)果返回。
例如我們對一個Array求和。
function sum(arr) {
return arr.reduce(function (x, y) {
return x + y;
});
}
sum([1, 2, 3, 4, 5]); // 15
但是當(dāng)他不需要立即求和,可以在后面的代碼里想計算時在計算。可以將這個函數(shù)當(dāng)做返回值。
function lazy_sum(arr){
var sum = function(){
return arr.reduce(function(x,y){
return x+y;
});
}
return sum;
}
所以當(dāng)我們調(diào)lazy_sum時,返回的并不是求和結(jié)果,而是求和函數(shù);
var f = lazy_sum([1,2,3,4,5]) //function sum()
f(); //15
2.閉包
在上面那個例子中,我們在函數(shù)lazy_sum中又定義了函數(shù)sum,并且,內(nèi)部函數(shù)sum可以引用外部函數(shù)lazy_sum的參數(shù)和局部變量,當(dāng)lazy_sum返回函數(shù)sum時,相關(guān)參數(shù)和變量都保存在返回的函數(shù)中,這種稱為“閉包(Closure)”的程序結(jié)構(gòu)擁有極大的威力。
使用閉包需要牢記一點(diǎn):返回函數(shù)不要引用任何循環(huán)變量,或者后續(xù)會發(fā)生變化的變量。
閉包的作用:
1)讀取函數(shù)內(nèi)部的變量
2)讓這些變量的值始終保持在內(nèi)存中
使用閉包的注意點(diǎn):
1)由于閉包會使得函數(shù)中的變量都被保存在內(nèi)存中,內(nèi)存消耗很大,所以不能濫用閉包,否則會造成網(wǎng)頁的性能問題,在IE中可能導(dǎo)致內(nèi)存泄露。解決方法是,在退出函數(shù)之前,將不使用的局部變量全部刪除。
2)閉包會在父函數(shù)外部,改變父函數(shù)內(nèi)部變量的值。所以,如果你把父函數(shù)當(dāng)作對象(object)使用,把閉包當(dāng)作它的公用方法(Public Method),把內(nèi)部變量當(dāng)作它的私有屬性(private value),這時一定要小心,不要隨便改變父函數(shù)內(nèi)部變量的值。
想要理解閉包,關(guān)鍵還是要從代碼中領(lǐng)悟,例子1:
function fun(n,o) {
console.log(o)
return {
fun:function(m){
return fun(m,n);
}
};
}
var a = fun(0); a.fun(1); a.fun(2); a.fun(3);//undefined,?,?,?
var b = fun(0).fun(1).fun(2).fun(3);//undefined,?,?,?
var c = fun(0).fun(1); c.fun(2); c.fun(3);//undefined,?,?,?
下面這三行分別輸出什么?
先看最外層的fun函數(shù),屬于標(biāo)準(zhǔn)的函數(shù)聲明,返回一個對象,對象為{fun:function(m)},可以看出這個對象為。fun屬性對應(yīng)一個匿名函數(shù),這個匿名函數(shù)形成一個閉包,?使得它可以訪問外部的變量n以及外層函數(shù)fun,所以這里第一個函數(shù)和第三個函數(shù)是相等的。
所以可以得知,最內(nèi)層的return出去的fun函數(shù)不是第二層fun函數(shù),是最外層的fun函數(shù).
第一題:
那么根據(jù)var a = fun(0), a實(shí)際上返回為:{fun:function(m)}
a.fun(1)等價為
function(1){
return fun(1,n);
}
由于這是一個閉包結(jié)構(gòu),可以訪問外部變量,于是n=0 ,所以返回的為fun(1,0),那么console.log(o)的值為0
同理:
a.fun(2)返回的為fun(2,0),那么console.log(o)的值為0
a.fun(3)返回的為fun(3,0),那么console.log(o)的值為0
第二題:
var b =fun(0).fun(1).fun(2).fun(3) 分別寫出他們的等價函數(shù)為
var b = fun(0) //undefine
var b =fun(0).fun(1)// fun(1,0) //console.log(o)結(jié)果0
var b =fun(0).fun(1).fun(2) //fun(2)=>fun(2,1) //console.log(o)結(jié)果1
var b =fun(0).fun(1).fun(2).fun(3) // =>fun(3,2) //console.log(o)結(jié)果2
第三題:
var c = fun(0).fun(1); c.fun(2); c.fun(3);
var c = fun(0).fun(1);// fun(1,0) //console.log(o)結(jié)果0
c.fun(2) =fun(0).fun(1).fun(2) //fun(2)=>fun(2,1) //console.log(o)結(jié)果1
c.fun(3) =fun(0).fun(1).fun(3) // =>fun(3,1) //console.log(o)結(jié)果1
所以只要掌握三個關(guān)鍵點(diǎn)就能很好的理解這個題目:
1.弄清楚每個函數(shù)的返回值,第一個函數(shù)返回對象,對象里面的函數(shù)返回的仍然是一個函數(shù)。
2.因?yàn)檫@個是閉包結(jié)構(gòu),所以對象里面返回的函數(shù)可以是外部函數(shù)。
3.因?yàn)檫@個是閉包結(jié)構(gòu),所以在內(nèi)部函數(shù)中引用了n的值之后,n的值會存在內(nèi)存中,所以n的值在返回函數(shù)里可以讀取到。