JavaScript 中的回调只是空白函数吗?

Are callbacks in JavaScript just blank functions?

我一直在努力研究回调,出于好奇,我在 todomvc 中查看 vanilla js 的源代码并找到了这个函数:

Store.prototype.findAll = function (callback) {
    callback = callback || function () {};
    callback.call(this, JSON.parse(localStorage[this._dbName]).todos);

};

下面的语句是什么意思?

callback = callback || function () {};

这是否意味着回调只是空白函数?

还有,有什么区别 callback.call(this)callback(anything)?

我试过修改这一行

callback.call(this, JSON.parse(localStorage[this._dbName]).todos);

callback(JSON.parse(localStorage[this._dbName]).todos);

但结果是一样的。为什么人们会做 callback.call 而不是简单地 callback

模式:

function foo(bar) {
  bar = bar || someDefault;
  ...
}

是一种常见(但已过时)的方法,用于在调用者未定义函数参数时将其设置为默认值。

在这种情况下,该函数利用所有函数为真和 callback 设置为空 (nop) 函数(如果未设置)。您可以在以下示例中看到该行为:

var barDefault = 'No value provided!';

function foo(bar) {
  bar = bar || barDefault;
  console.log(bar);
}

foo(); // No value provided, since no arguments passed
foo(3); // Argument passed, value provided
foo(0); // Tricky case: falsy argument passed, so function assumes no value was provided

正如您从示例中看到的那样,当传递的参数为假时,此模式可能会导致问题,因为 OR 运算符将回退到默认值。要解决这个问题,请使用:

bar = typeof bar !== 'undefined' ? bar : barDefault;

将显式检查未定义的参数。

使用 ES6 和默认参数值,这可以更地道地表达为:

function foo(bar = someDefault) {
  ...
}

不,回调不是 "just blank"。这里函数接收回调作为参数,并简单地确保它是 a 函数。如果没有传递回调,它将被设置为一个空函数,但至少它是可以调用的 a 函数。将参数设置为默认值(这里是一个空函数)可以简化以下代码,否则如果回调不是函数,则需要一堆 if..else 条件来做一些不同的事情。

关于问题的其他部分,请参阅 How does the "this" keyword work?

Are callbacks in JavaScript just blank functions?

回调不仅仅是空白函数。它们是可以稍后调用(通常带有一些参数)的函数。有时,它们是可选的,宿主函数会让您传递回调或不传递回调。如果未传递回调,宿主函数可以检测到它未作为参数传递并相应地调整其行为。

What does the following statement mean?

callback = callback || function () {};

Does that mean callbacks are simply blank functions?

这是一种常见的设计模式,可确保函数的参数在调用者未传递的情况下具有有意义的值,因此函数可以在内部继续并在假定参数由调用者传递的情况下正常执行,即使调用者没有传递参数。

代码callback = callback || function () {};等同于:

if (callback) {
    callback = callback;
} else {
    callback = function() {};
}

在 Javascript 中,|| 运算符将结果分配为两个操作数中第一个为真(或 false,如果两者都不为真)的结果,因此如果 callback 有一个值,然后它成为 || 操作数的结果,你得到 callback = callback。否则,如果 callback 不为真,它会为 callback 分配一个默认函数值,允许函数的其余部分在假设 callback 具有合法值的情况下运行。这使得所有其余的函数代码在使用它之前不必检查 callback 是否具有合法值。

Also, what's the difference between callback.call(this) and callback(anything)?

someFunction.call() 允许您在函数运行时使用 this 的值。因此 callback.call(this) 使回调在运行时具有与当前函数相同的 this 值。如果你只是在没有 .call() 的情况下执行 callback(...),那么 this 将采用默认值,它是 window 对象,或者如果 运行 在严格模式下, 它将是 undefined.

如果特定的回调在其代码中没有碰巧引用 this 的值,那么使用 .call() 或不使用它的结果都没有区别,但在在这种情况下,它是提供给回调的额外功能,它可以通过访问回调内的 this 值来访问正在使用的 Store 对象的当前实例。


像这样设置 this 的值允许您使用对象的方法作为直接回调,因为这与对象方法具有相同的调用约定。

所以,如果您有一个像这样的 Store 对象:

var s = new Store();

而且,那个对象有一个名为 setName() 的方法,它使用 this 来引用它自己的对象实例,你可以这样做:

s.findAll(s.setName);

这只会起作用,因为 callback.call(this) 在回调中将实例值设置为 this 的值。