当我第一次学习编程时,它帮助我将函数理解为机器。这些机器可以做任何你想要的东西。他们甚至可以接受输入并返回一个值。每台机器上都有一个按钮,你可以在需要机器运行时按下该按钮,即()。
function add (x, y) {
return x + y
}
add(2,3) // 5 - 按下按钮,执行机器
复制代码无论我按下按钮,你按下按钮,或者别人按下按钮无所谓。无论何时按下按钮,机器都将运行。
function add (x, y) {
return x + y
}
const me = add
const you = add
const someoneElse = add
me(2,3) // 5 - Press the button, run the machine.
you(2,3) // 5 - Press the button, run the machine.
someoneElse(2,3) // 5 - Press the button, run the machine.
复制代码在上面的代码,我们分配add函数,三个不同的变量,me,you,和someoneElse。重要的是要注意add我们创建的原始变量和每个变量都指向内存中的相同位置。它们在不同的名称下完全相同。所以,当我们调用me时you,或者someoneElse,就好像我们正在调用一样add函数。
现在如果我们把add机器送到另一台机器怎么办?请记住,按下()按钮并不重要,如果按下它,它就会运行。
function add (x, y) {
return x + y
}
function addFive (x, addReference) {
return addReference(x, 5) // 15 - Press the button, run the machine.
}
addFive(10, add) // 15
复制代码你的大脑可能在这一点上有点奇怪,但这里没有新的东西。我们不是“按下按钮” add,而是add作为参数传递addFive,重命名它addReference,然后我们“按下按钮”或调用它。
这突出了JavaScript语言的一些重要概念。首先,正如你可以将字符串或数字作为参数传递给函数一样,你也可以将函数的引用作为参数传递。当执行此操作时,作为参数传递的函数称为回调函数,并且将回调函数传递给的函数称为高阶函数。
因为词汇很重要,所以这里的代码与重新命名的变量相同,以匹配他们演示的概念。
function add (x,y) {
return x + y
}
function higherOrderFunction (x, callback) {
return callback(x, 5)
}
higherOrderFunction(10, add)
复制代码这种模式应该看起来很熟悉,无处不在。如果你曾经使用过任何JavaScript Array方法,那么你已经使用了回调。如果你曾经使用过lodash,那么你已经使用过回调。如果你曾经使用过jQuery,那么你已经使用了回调。
[1,2,3].map((i) => i + 5)
_.filter([1,2,3,4], (n) => n % 2 === 0 );
$('#btn').on('click', () =>
console.log('Callbacks are everywhere')
)
复制代码通常,回调有两种常见的用例。第一,我们看下.map和_.filter例子,是翻转一个值到另一个很好的抽象。我们说“嘿,这是一个数组和一个函数。来吧,根据我给你的函数给我一个新的值“。第二个,也就是我们在jQuery示例中看到的,是将函数的执行延迟到特定时间。“嘿,这是这个函数。每当btn点击具有id的元素时,请继续调用它。“这是我们将关注的第二个用例,”延迟执行函数直到特定时间“。
现在我们只看了同步的例子。正如我们在本文开头所讨论的那样,我们构建的大多数应用程序都没有预先获得所需的所有数据。相反,他们需要在用户与应用程序交互时获取外部数据。我们刚刚看到回调如何成为一个很好的用例,因为它们再次允许你“延迟执行函数直到特定时间”。看看我们如何使该句子适应数据提取并不需要太多想象力。我们可以延迟函数的执行,直到我们获得所需的数据,而不是将函数的执行延迟到特定时间。这可能是最流行的例子,jQuery的方法:getJSON。
// updateUI and showError are irrelevant.
// Pretend they do what they sound like.
const id = 'tylermcginnis'
$.getJSON({
url: `https://api.github.com/users/${id}`,
success: updateUI,
error: showError,
})
复制代码在获得用户数据之前,我们无法更新应用的UI。那么我们该怎么办?我们说,“嘿,这是一个对象。如果请求成功,请继续调用success并传递用户的数据。如果没有,请继续调用error并传递错误对象。你不需要担心每种方法的作用,只要确保在你应该的时候调用它们。这是使用异步请求回调的完美演示。
在这一点上,我们已经了解了回调是什么以及它们如何在同步和异步代码中都有用处的。我们还没有谈到的是回调的黑暗面。请看下面的代码。你能说出发生了什么吗?
// updateUI, showError, and getLocationURL are irrelevant.
// Pretend they do what they sound like.