所谓的“一等公民”,其实就是普通公民。也就是说,函数其实没有什么特殊的,我们可以像对待任何其他数据类型一样对待函数。
我们可以把函数赋值给一个变量。
var fn = function() {}
我们可以把函数存在数组里。
var fn = function() {}
var array = [0, 2, 'te', fn];
我们可把函数当做一个参数传入另外一个函数中。
function fn(callback) {
var a = 20;
return callback(20, 30) + a;
}
function add(a, b) {
return a + b;
}
fn(add); // 70
我们也可以把函数作为另一个函数运行的返回值。
function add(x) {
var y = 20;
return function() {
return x + y;
}
}
var _add = add(100);
_add(); // 120
当然,这都是JavaScript的基本概念。但是我想很多人,甚至包括正在阅读的你自己都可能会无视这些概念。可以用一个简单的例子来验证一下。
我们先自定义如下这样一个函数,要求在5000ms之后执行该函数我们应该怎么做?大家思考10秒钟再往下看吧。
function delay() {
console.log('5000ms之后执行该函数。');
}
我敢肯定有人会如下这样想。
var timer = setTimeout(function() {
delay();
}, 5000);
很显然,这样做能够达到我们的目的,但这也正是我们忽视了上面的概念写出来的糟糕代码。
函数既然能够作为一个参数传入另外一个函数,那么我们是不是可以直接将delay函数传入而不用在固有的思维上额外在封装一层多余的function?
var timer = setTimeout(delay, 5000);
当然,如果你已经提前想到这样做了,那么恭喜你,说明你在JavaScript上还是更有天赋。第一种方式的糟糕写法许多人都一直在使用,而他自己还不知道自己问题所在。
这种方式再未来还会遇到很多次,如果你没有特别关注,可能你仍然会写出糟糕的方式。为了验证大家确实理解了,现在我们需要大家思考一下如何优化下面的例子。
function getUser(path, callback) {
return $.get(path, function(info) {
return callback(info);
})
}
getUser('/api/user', function(resp) {
// resp为成功请求之后返回的数据
console.log(resp);
})
在这个例子中,我们期望封装一个获取用户信息的函数。并期望在请求成功之后需要处理的事情放在回调函数callback中来做。
当然大家也不要花太多时间去思考,我们一起来分析一下。先看看getUser这个方法内部的实现。
$.get(path, function(info) {
return callback(info);
})
看着一段代码,是不是和上面setTimeout的例子一模一样?我们会发现其实callback函数被额外包裹了一层没有意义的函数。因此我们第一步就是需要把这一步简化。
$.get(path, callback);
于是最初的例子其实等同于如下:
function getUser(path, callback) {
return $.get(path, callback);
}
但是我们再仔细观察,是不是又发现了同样的问题,$.get方法也同样的被包裹了一层没有意义的函数。因此再优化,则得到如下的结果。
// $.get是jquery自带的工具方法
var getUser = $.get;
嗯,是不是很神奇,到最后才发现我们干了一件脱了裤子放屁的事情。
当然,可能会有一部分人对于参数的处理有一些疑问。那么可以通过下面的例子来进行简单的类比。
function add(a, b) {
return a + b;
}
var other = add;
other(10, 20); // 30
在未来的coding中,我们还会遇到非常多这种类似的情形,如果你能够意识到,自己正在正确的使用函数一等公民的身份,那么恭喜你,你对函数的理解,已经先人一步。