因为在ECMAScript中,函数名本身就是变量,所以函数也可以作为值来使用。也就是说,不仅可以像传递参数一样把一个函数传递给另一个函数,而且可以将一个函数作为另一个函数的结果返回。
1. 作为参数
来看一个示例:
function callFn(fn, param){
return fn(param);
}
function add5(num){
return num + 5;
}
var value = callFn(add5, 10);
console.log(value);//15
首先声明了一个callFn
函数,它接收两个参数,一个是要调用的函数,另一个是传递给要调用函数的参数。接下来创建了add5
函数,然后使用callFn
调用了add5
,返回了add5
的结果。
其实这里使用匿名函数作为参数也是可以的,还是这个例子:
var value = callFn(function(num){
return num + 5;
}, 10);
console.log(value);//15
看到这是不是觉得有点熟悉呢?其实类似的,我们一直在用:
setTimeout(function(){
console.log('hello world');
}, 1000);
上面这段代码我想读者一定不陌生吧,这是一个延迟函数,1秒钟后执行第一个参数——匿名函数。setTimeout
是一个定义在window
上的全局函数,第一个参数是要执行的回调函数,第二个参数是延迟的毫秒数。
再来看另一个例子:
$('#id').click(function(){
console.log('点击了');
});
这是jQuery中的写法,$()
是一个函数调用,这个函数接收的参数是'#id'
,返回了一个jQuery对象,在这个对象上再调用click()
方法,这个方法接收一个匿名函数作为参数,这样就完成了click事件的绑定。
下面是jQuery 3.3.1版本131~144行的代码,我们看到jQuery
就是一个函数。
var
version = "3.3.1",
// Define a local copy of jQuery
jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
// Need init if jQuery is called (just allow error to be thrown if not included)
return new jQuery.fn.init( selector, context );
},
// Support: Android <=4.0 only
// Make sure we trim BOM and NBSP
rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
这是第10333~10358行:
var
// Map over jQuery in case of overwrite
_jQuery = window.jQuery,
// Map over the $ in case of overwrite
_$ = window.$;
jQuery.noConflict = function( deep ) {
if ( window.$ === jQuery ) {
window.$ = _$;
}
if ( deep && window.jQuery === jQuery ) {
window.jQuery = _jQuery;
}
return jQuery;
};
// Expose jQuery and $ identifiers, even in AMD
// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
// and CommonJS for browser emulators (#13566)
if ( !noGlobal ) {
window.jQuery = window.$ = jQuery;
}
对于其中的逻辑我们大可不必理会,从中可以看出,这段代码大致做了这样一件事:
window.jQuery = window.$ = jQuery;
这样就能理解,为什么我们可以使用$()
了,$()
和jQuery()
是等同的。
2. 作为返回值
先来看一段代码:
var arr = [8, 1, 35, 3, 10];
//升序
function ascSort(v1, v2) {
return v1 - v2;
}
arr.sort(ascSort);
console.log(arr);//[1, 3, 8, 10, 35]
//降序
function descSort(v1, v2){
return v2 - v1;
}
arr.sort(descSort);
console.log(arr);//[35, 10, 8, 3, 1]
这是JavaScript数组(一)——排序中讲的给数组排序的代码,我们看到升序和降序分别声明了一个函数,现在我们想能不能把这两个函数合并为一个呢?来看下面的代码:
var arr = [8, 1, 35, 3, 10];
function comparisonFn(flag){
if(flag){
// true 升序
return function(v1, v2){
return v1 - v2;
}
}else{
// false 降序
return function(v1, v2){
return v2 - v1;
}
}
}
arr.sort(comparisonFn(false));
console.log(arr);//[35, 10, 8, 3, 1]
如代码所示,我们创建了一个函数,把真正的比较函数作为这个函数的返回值,在使用的时候通过给comparisonFn()
传递true/false
来控制升降序,达到了简化代码的目的。
关于函数作为参数和返回值的例子还有很多,这里就不一一列举了,相信读者随着对JavaScript学习的不断深入,以后还会经常遇到的。