为什么我不能直接将console.log()设置为回调函数

Kot*_*aro 3 javascript callback this console.log

为什么这段代码不起作用

function callback(num, func) {
    for(var i = 0; i < num; i++) {
        func();
    }
}

callback(4, console.log("Hello"));
Run Code Online (Sandbox Code Playgroud)

我知道我必须这样做:

callback(4, function() { console.log("hello"); });
Run Code Online (Sandbox Code Playgroud)

但我仍然不明白我必须这样做的原因.

Emi*_*ary 5

让我们一步一步地帮助您想象正在发生的事情.当解释器读取您的代码时,它会从里到外评估函数表达式.也就是说:

callback(4, console.log("Hello"));
//          ^------------------^---- is evaluated before "callback" is called.
Run Code Online (Sandbox Code Playgroud)

编写这种产生相同结果的较长形式的方法是:

var result = console.log("Hello");
callback(4, result);
Run Code Online (Sandbox Code Playgroud)

console.log函数没有定义的返回值(或者至少不是标准的返回值) - 尽管javascript中的所有函数都返回了一些东西 - 当未指定时,这个值是字面意思undefined.因此,当您运行代码时,您实际上是在调用:

callback(4, undefined);
Run Code Online (Sandbox Code Playgroud)

这意味着在内部callback,尝试func作为函数调用将导致:

TypeError:undefined不是函数

这就是为什么你需要在新的函数闭包中封装你的逻辑 - 从而func获得对可调用Function对象的引用.


那么如何整理我的代码呢?

通常在这样的简单情况下,你所做的解决问题是完全可以接受的,但是对于更复杂的逻辑,你通常会得到几层嵌套回调(有时也称为"回调 - 汤").为了提高代码重用的可读性,您可以引入一个隐藏恶劣的函数工厂,例如:

function myLogger(message){
    return function(){
        console.log(message);
    }      
}

callback(4, myLogger('hello'));
Run Code Online (Sandbox Code Playgroud)