在JS中,函数是一等公民。这该怎么理解?为什么说它是“一等”的呢?其实这体现在函数可以去任何值可以去的地方,很少有限制。
- 函数可以存储为变量
- 函数可以存储为数组元素
- 函数可以成为对象的成员变量
- 函数可以在使用时直接创建出来
- 函数可以传递给另一个函数
- 函数可以被另一个函数返回
最后两点其实就是高阶函数的定义,一个高阶函数可以执行以下至少一项操作:以一个函数作为参数、返回一个函数作为结果。
这两点是不是有点眼熟?没错,还记得闭包的应用场景么?闭包函数作为返回值 和 闭包函数作为参数传递。再进一步回忆下,闭包函数中的自由变量取值自哪里?自由变量的值从函数创建时所处作用域中取得,划重点是
创建
时,而非调用
时。
闭包就是一个普通函数,在该函数生成时会“捕获”附近的值。这个“附近”指的是该函数创建时所处的作用域,这个值就是闭包函数中的自由变量的值。
组织一下语言的表述:闭包就是一个函数,与普通函数的区别在于,它能捕获自身创建时所处作用哉中的值作为自己作用哉内自由变量的值,这个捕获的值可以是任何类型,包括函数,并且该闭包函数在其他作用域中被调用时,仍然能保持对该自由变量值的引用。
闭包最简单的例子就是捕获局部变量:
function whatWasTheLocal() {
var captured = 'oh hai'; //局部变量
return function () {
return 'The local was ' + captured; //捕获局部变量
}
}
var res = whatWasTheLocal();
console.log(res()); //The local was oh hai
局部变量captured
的 生命周期只限于函数体内,但是当被一个闭包函数捕获后,它在其他地方调用这个闭包函数时,还会继续存在。
除了捕获局部变量,闭包函数也可以捕获函数参数:
function fn(rate) {
return function (arr) {
return arr.map(function (v, i) {
return v*rate; //闭包函数捕获创建时所处作用域中的函数参数值
})
}
}
var fn10 = fn(10);
console.log(fn10([2, 4, 5])); //[ 20, 40, 50 ]
在《JavaScript函数式编程》中看到对闭包有这样的比喻,我觉得非常形象,在此分享下:闭包函数尤如一个吸血鬼,捕获一个部下后给其永久的生命以供驱策,直到这个吸血鬼被摧毁,它的部下才会随之解放并毁灭。
类比闭包,闭包捕获一个其创建时所处作用域中的变量以供其使用,即使该变量所处作用域在程序执行下去时已经销毁,但该变量值由于仍始终被闭包引用,所以系统回收机制会始终视而不见让它一直活着,直到这个闭包被主动销毁,其所链接的那个变量才会被系统认定再无引用而被回收机制回收。
闭包的强大在于可以帮助开发者更方便的抽象,例如:
function getVal(field) {
return function (obj) {
return (obj && obj[field])
}
}
var obj = {name: 'nitx', job: 'f2e', age: 30};
console.log(getVal('name')(obj)); //nitx
上例中的obj对象也可以换成数组。
在JS的函数式编程中,其实一直在玩的是变量作用域和闭包。无论是普通函数还是闭包函数,首先是理解变量作用域,它是函数各种玩法的理论基础,在理解透变量作用域的前提下,才能明白闭包的真正强大之处。
喜欢本文请扫下方二维码,关注微信公众号: 前端小二,查看更多我写的文章哦,多谢支持。