为什么不能直接设置console.log()为回调函数
Why I can't directly set console.log() as callback function
为什么这段代码不起作用
function callback(num, func) {
for(var i = 0; i < num; i++) {
func();
}
}
callback(4, console.log("Hello"));
我知道我必须这样做:
callback(4, function() { console.log("hello"); });
但我还是不明白我为什么要那样做。
那是因为当你提到 console.log() 时,你要求 js 引擎对其求值,它确实将结果作为第二个参数传递给回调函数,而不是它期望的函数对象,并且因此,电话的行为并不如您所愿。
当您传递 function(){} 构造时,工作案例会正确传递函数对象。
如果您将 console.log('foo') 作为回调,您将调用日志 return 作为函数。
一个解决方案是将你的 console.log 放在一个函数中:
function callback(num, func) {
for(var i = 0; i < num; i++)
func();
}
callback(4, function(){
console.log("Hello2")
});
因为函数是 Javascript 中的第一个 class 公民(意思是函数可以存储在变量中)。将函数作为参数传递将 return 对函数定义的引用,而不是您尝试调用的函数调用。
但是,它确实会事先评估您的 console.log 并将其作为变量传递,并且由于您的日志函数调用没有 return 任何未定义的传递给您的回调函数。
function test( logFunction ){
logFunction( 'test' )
}
test( alert )
是这种行为的一个例子。这也是像 Remy J 所演示的那种闭包起作用的原因。
function callback(num, func) {
for(var i = 0; i < num; i++) {
func( "Hello" );
}
}
callback(4, alert);
这行得通。
让我们逐步了解它以帮助您直观地了解正在发生的事情。当解释器读取您的代码时,它会从内到外计算函数表达式。也就是说:
callback(4, console.log("Hello"));
// ^------------------^---- is evaluated before "callback" is called.
产生相同结果的更长形式的写法是:
var result = console.log("Hello");
callback(4, result);
console.log
函数没有定义的 return 值(或者至少不是标准化值)——尽管 javascript return return something - 当未指定时,此值字面意思是 undefined
。因此,当您 运行 您的代码实际上是在调用:
callback(4, undefined);
这意味着在 callback
中,尝试将 func
作为函数调用将导致:
TypeError: undefined is not a function
这就是为什么您需要将您的逻辑封装在一个新的函数闭包中 - func
借此获得对可调用 Function
对象的引用。
那么如何整理我的代码?
通常在像这样的简单情况下,您为解决问题所做的工作是完全可以接受的,但是对于更复杂的逻辑,您通常会以多层嵌套回调(有时称为 "callback-soup")。为了提高代码重用常见的可读性,您可以引入一个隐藏脏东西的函数工厂,例如:
function myLogger(message){
return function(){
console.log(message);
}
}
callback(4, myLogger('hello'));
为什么这段代码不起作用
function callback(num, func) {
for(var i = 0; i < num; i++) {
func();
}
}
callback(4, console.log("Hello"));
我知道我必须这样做:
callback(4, function() { console.log("hello"); });
但我还是不明白我为什么要那样做。
那是因为当你提到 console.log() 时,你要求 js 引擎对其求值,它确实将结果作为第二个参数传递给回调函数,而不是它期望的函数对象,并且因此,电话的行为并不如您所愿。 当您传递 function(){} 构造时,工作案例会正确传递函数对象。
如果您将 console.log('foo') 作为回调,您将调用日志 return 作为函数。
一个解决方案是将你的 console.log 放在一个函数中:
function callback(num, func) {
for(var i = 0; i < num; i++)
func();
}
callback(4, function(){
console.log("Hello2")
});
因为函数是 Javascript 中的第一个 class 公民(意思是函数可以存储在变量中)。将函数作为参数传递将 return 对函数定义的引用,而不是您尝试调用的函数调用。 但是,它确实会事先评估您的 console.log 并将其作为变量传递,并且由于您的日志函数调用没有 return 任何未定义的传递给您的回调函数。
function test( logFunction ){
logFunction( 'test' )
}
test( alert )
是这种行为的一个例子。这也是像 Remy J 所演示的那种闭包起作用的原因。
function callback(num, func) {
for(var i = 0; i < num; i++) {
func( "Hello" );
}
}
callback(4, alert);
这行得通。
让我们逐步了解它以帮助您直观地了解正在发生的事情。当解释器读取您的代码时,它会从内到外计算函数表达式。也就是说:
callback(4, console.log("Hello"));
// ^------------------^---- is evaluated before "callback" is called.
产生相同结果的更长形式的写法是:
var result = console.log("Hello");
callback(4, result);
console.log
函数没有定义的 return 值(或者至少不是标准化值)——尽管 javascript return return something - 当未指定时,此值字面意思是 undefined
。因此,当您 运行 您的代码实际上是在调用:
callback(4, undefined);
这意味着在 callback
中,尝试将 func
作为函数调用将导致:
TypeError: undefined is not a function
这就是为什么您需要将您的逻辑封装在一个新的函数闭包中 - func
借此获得对可调用 Function
对象的引用。
那么如何整理我的代码?
通常在像这样的简单情况下,您为解决问题所做的工作是完全可以接受的,但是对于更复杂的逻辑,您通常会以多层嵌套回调(有时称为 "callback-soup")。为了提高代码重用常见的可读性,您可以引入一个隐藏脏东西的函数工厂,例如:
function myLogger(message){
return function(){
console.log(message);
}
}
callback(4, myLogger('hello'));