为什么我可以't直接将console.log()设置为回调函数

Why I can't directly set console.log() as callback function

本文关键字:log 设置 函数 回调 console 我可以 为什么      更新时间:2023-09-26

为什么此代码不适用于

function callback(num, func) {
    for(var i = 0; i < num; i++) {
        func();
    }
}
callback(4, console.log("Hello"));

我知道我必须这样做:

callback(4, function() { console.log("hello"); });

但我仍然不明白为什么我必须这样做。

让我们逐步了解它,帮助您可视化正在发生的事情。当解释器读取您的代码时,它会对函数表达式进行内部求值。也就是说:

callback(4, console.log("Hello"));
//          ^------------------^---- is evaluated before "callback" is called.

写这篇文章的一种更长的方式会产生同样的结果:

var result = console.log("Hello");
callback(4, result);

console.log函数没有定义的返回值(或者至少没有标准化的返回值)——尽管顺便说一句,javascript中的所有函数都会返回东西——当未指定时,这个值实际上就是undefined。因此,当你运行你的代码时,你本质上是在调用:

callback(4, undefined);

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

TypeError:undefined不是函数

这就是为什么您需要将逻辑封装在一个新的函数闭包中——func由此获得对可调用Function对象的引用。


那么我如何整理我的代码

一般来说,在这种简单的情况下,你为解决问题所做的一切都是完全可以接受的,但对于更复杂的逻辑,你通常会得到几个级别的嵌套回调(有时被称为"回调汤")。为了提高代码重用的可读性,你可以引入一个函数工厂来隐藏这些肮脏的东西,例如:

function myLogger(message){
    return function(){
        console.log(message);
    }      
}
callback(4, myLogger('hello'));

这是因为当你提到console.log()时,你要求js引擎对它进行评估,它会这样做,并将结果作为第二个参数传递给回调函数,而不是它期望的函数对象,因此调用的行为不像你期望的那样。当您传递function(){}构造时,工作案例会正确地传递函数对象。

如果将console.log('fo')作为回调函数,则会将日志返回作为函数调用。

一个解决方案是将console.log放入一个函数中:

function callback(num, func) {
   for(var i = 0; i < num; i++)
      func();
}
callback(4, function(){
   console.log("Hello2")
});

因为函数在Javascript中是一流的citiziens(意味着函数可以存储在变量中)。将函数作为参数传递将返回对函数定义的引用,而不是您试图调用的函数调用。然而,它会预先评估console.log并将其作为变量传递,由于日志的函数调用不会返回任何内容,因此它会将未定义的内容传递给回调函数。

function test( logFunction ){
    logFunction( 'test' )
}
test( alert )

就是这种行为的一个例子。这也是像雷米J作品中所展示的那种闭包的原因。

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

这是可行的。