所谓的“一等公民”,其实就是普通公民。也就是说,函数其实没有什么特殊的,我们可以像对待任何其他数据类型一样对待函数。

我们可以把函数赋值给一个变量。

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中,我们还会遇到非常多这种类似的情形,如果你能够意识到,自己正在正确的使用函数一等公民的身份,那么恭喜你,你对函数的理解,已经先人一步。

results matching ""

    No results matching ""