为什么此代码不起作用
function callback(num, func) {
for(var i = 0; i < num; i++) {
func();
}
}
callback(4, console.log("Hello"));
我知道我必须这样做:
callback(4, function() { console.log("hello"); });
但我仍然不明白我必须这样做的原因。
答案 0 :(得分:5)
让我们一步一步地帮助您想象正在发生的事情。当解释器读取您的代码时,它会从里到外评估函数表达式。也就是说:
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
对象的引用。
那么如何整理我的代码?
通常在这样的简单情况下,你为解决问题所做的工作是完全可以接受的,但是对于更复杂的逻辑,你通常会得到几层嵌套回调(有时也称为“callback-soup “)。为了提高代码重用的可读性,您可以引入一个隐藏恶劣的函数工厂,例如:
function myLogger(message){
return function(){
console.log(message);
}
}
callback(4, myLogger('hello'));
答案 1 :(得分:0)
那是因为当你提到console.log()时,你要求js引擎对它进行评估并将其作为第二个arg传递给回调函数而不是它所期望的函数对象,因此调用不会不如你所愿。 当你传递一个function(){}构造时,工作案例正确地传递了一个函数对象。
答案 2 :(得分:0)
如果您将console.log('foo')作为回调,则将日志返回作为函数调用。
解决方案是将您的console.log放在一个函数中:
function callback(num, func) {
for(var i = 0; i < num; i++)
func();
}
callback(4, function(){
console.log("Hello2")
});
答案 3 :(得分:0)
因为函数是Javascript中的第一类公用事业(意味着函数可以存储在变量中)。将函数作为参数传递将返回对函数定义的引用,而不是您尝试调用的函数调用。 但它会预先评估您的console.log并将其作为变量传递,因为您的日志函数调用不会将未定义的任何内容返回给您的回调函数。
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);
这样可行。