为什么回调必须是一个函数?
Why do callbacks have to be a function?
我一直在看:
() => execute code
而不只是
execute code
在回调中。我没有传递任何参数,那么为什么 () => execute code 有效而 execute code 却没有?它们不是一回事吗,因为一个函数只代表几行代码?我在其他语言中也看到了类似的东西,比如 java 其中使用了 lambda
谢谢。
使用回调是因为函数需要在未来某个不确定的时间点被调用——代码需要执行。简单地执行 javascript 中的代码将始终立即执行它。如果您需要执行一些异步任务并且 then 做某事,这没有帮助。
例如,setTimeout()
因为需要等待而接受回调,然后然后做一些事情:
//In about 1500 ms setTimeout will call this ()=>{} function
setTimeout(() => {
console.log("finished")
}, 1500)
能够像这样传递一个函数是非常灵活的,因为函数也可以接受参数和 return 值,这些值可以在调用函数时确定。如果代码没有组织在一个函数中,那将更加困难或不可能。
如果我直接传入一个表达式,它会立即执行:
// console.log runs immediately, there's not way to defer it.
setTimeout( console.log("finished")
, 1000)
所以函数不仅仅代表一些代码,它代表一个可以调用的动作。它可以由您调用,也可以由其他函数调用,例如 setTimeout 或特定时间的 HTTP 请求。
你看到的是Javascript中的一个函数,叫做Arrow Function,可以这样写:
单行如果return一个操作:
const f = (a,b) => return a+b;
或更多操作的行块:
const f = (a,b) => { c = a + b; return c};
需要该函数才能知道不应立即执行代码。
如果你会使用
myFunction(myArg, window.location.href='https://www.whosebug.com');
而不是
myFunction(myArg, () => {
window.location.href='https://www.whosebug.com';
});
在第一种情况下,语言无法知道代码应该作为回调在稍后执行。
因此,它会在方法被调用时立即执行,这会导致传递布尔值而不是回调函数。在这种情况下,即使调用的函数没有完全 运行,页面也会立即打开,而不是在作为回调执行后切换到 whosebug.com。
简而言之,函数允许 运行 稍后通过调用它包含的代码。
通常会将带有结果的参数传递给回调,以便处理这些结果。
因为如果按照你建议的方式去做,代码会立即执行;即,当您拨打电话时。
你需要明白
() -> doSomething()
和
doSomething()
意味着不同的事情(以后做与现在做)并评估不同的值。他们甚至没有相同的类型。假设 doSomething()
returns SomeType
:
- lambda 表达式计算为与
Supplier<SomeType>
和 兼容的对象
- 调用计算出一个与
SomeType
. 兼容的对象
我想您认为如果可以对这两种情况使用相同的语法并让编译器根据上下文找出正确的含义会很好。这有两个问题:
这会使代码更难理解。当您阅读某人的代码时,您需要知道每个表达式的每个参数是否期望具有立即评估语义(如方法调用)或延迟评估语义(如 lambda)的内容。
早在 1960 年代,他们就设计并实现了一种像这样工作的编程语言。 (查找 Algol-60 和 "call by name"。)这是一个错误。使用 call-by-name 的 Algol-60 程序 很难理解。 AFAIK,从那以后,这个错误在任何主流编程语言中都没有重复过。
您仍然需要声明参数是具有立即求值语义还是惰性求值语义。我认为不可能推断方法声明中需要哪些。
区别在于() => console.log('execute code')
是函数定义,而console.log('execute code')
是函数调用。
函数定义主体中的代码在函数被调用之前不会运行。
var double = (num) => console.log(num + num) // function definition, does nothing
double(2) // function invocation, logs 4 to the console
当您将函数定义作为参数传递给函数调用时,您就可以在被调用函数的主体内访问或调用传入的函数定义。
相反,如果您将函数 调用 作为参数传递给另一个函数调用,例如 double(2)
double(2)
(在本例中为 undefined
,因为 console.log
没有 return 值)在它被传入的函数体中可用。
示例:
var double = (num) => console.log(num + num)
var invokeCallbackAfterFiveSeconds = (callback) => {
setTimeout(callback, 5000);
};
//Passing in a function definition below...
invokeCallbackAfterFiveSeconds(() => double(3));
// ^ Will log 6 to the console after a five second delay
//Passing in a function invocation below...
invokeCallbackAfterFiveSeconds(double(4));
// ^ Will log 8 to the console immediately, then do nothing else.
我一直在看:
() => execute code
而不只是
execute code
在回调中。我没有传递任何参数,那么为什么 () => execute code 有效而 execute code 却没有?它们不是一回事吗,因为一个函数只代表几行代码?我在其他语言中也看到了类似的东西,比如 java 其中使用了 lambda
谢谢。
使用回调是因为函数需要在未来某个不确定的时间点被调用——代码需要执行。简单地执行 javascript 中的代码将始终立即执行它。如果您需要执行一些异步任务并且 then 做某事,这没有帮助。
例如,setTimeout()
因为需要等待而接受回调,然后然后做一些事情:
//In about 1500 ms setTimeout will call this ()=>{} function
setTimeout(() => {
console.log("finished")
}, 1500)
能够像这样传递一个函数是非常灵活的,因为函数也可以接受参数和 return 值,这些值可以在调用函数时确定。如果代码没有组织在一个函数中,那将更加困难或不可能。
如果我直接传入一个表达式,它会立即执行:
// console.log runs immediately, there's not way to defer it.
setTimeout( console.log("finished")
, 1000)
所以函数不仅仅代表一些代码,它代表一个可以调用的动作。它可以由您调用,也可以由其他函数调用,例如 setTimeout 或特定时间的 HTTP 请求。
你看到的是Javascript中的一个函数,叫做Arrow Function,可以这样写:
单行如果return一个操作:
const f = (a,b) => return a+b;
或更多操作的行块:
const f = (a,b) => { c = a + b; return c};
需要该函数才能知道不应立即执行代码。
如果你会使用
myFunction(myArg, window.location.href='https://www.whosebug.com');
而不是
myFunction(myArg, () => {
window.location.href='https://www.whosebug.com';
});
在第一种情况下,语言无法知道代码应该作为回调在稍后执行。 因此,它会在方法被调用时立即执行,这会导致传递布尔值而不是回调函数。在这种情况下,即使调用的函数没有完全 运行,页面也会立即打开,而不是在作为回调执行后切换到 whosebug.com。
简而言之,函数允许 运行 稍后通过调用它包含的代码。
通常会将带有结果的参数传递给回调,以便处理这些结果。
因为如果按照你建议的方式去做,代码会立即执行;即,当您拨打电话时。
你需要明白
() -> doSomething()
和
doSomething()
意味着不同的事情(以后做与现在做)并评估不同的值。他们甚至没有相同的类型。假设 doSomething()
returns SomeType
:
- lambda 表达式计算为与
Supplier<SomeType>
和 兼容的对象
- 调用计算出一个与
SomeType
. 兼容的对象
我想您认为如果可以对这两种情况使用相同的语法并让编译器根据上下文找出正确的含义会很好。这有两个问题:
这会使代码更难理解。当您阅读某人的代码时,您需要知道每个表达式的每个参数是否期望具有立即评估语义(如方法调用)或延迟评估语义(如 lambda)的内容。
早在 1960 年代,他们就设计并实现了一种像这样工作的编程语言。 (查找 Algol-60 和 "call by name"。)这是一个错误。使用 call-by-name 的 Algol-60 程序 很难理解。 AFAIK,从那以后,这个错误在任何主流编程语言中都没有重复过。
您仍然需要声明参数是具有立即求值语义还是惰性求值语义。我认为不可能推断方法声明中需要哪些。
区别在于() => console.log('execute code')
是函数定义,而console.log('execute code')
是函数调用。
函数定义主体中的代码在函数被调用之前不会运行。
var double = (num) => console.log(num + num) // function definition, does nothing
double(2) // function invocation, logs 4 to the console
当您将函数定义作为参数传递给函数调用时,您就可以在被调用函数的主体内访问或调用传入的函数定义。
相反,如果您将函数 调用 作为参数传递给另一个函数调用,例如 double(2)
double(2)
(在本例中为 undefined
,因为 console.log
没有 return 值)在它被传入的函数体中可用。
示例:
var double = (num) => console.log(num + num)
var invokeCallbackAfterFiveSeconds = (callback) => {
setTimeout(callback, 5000);
};
//Passing in a function definition below...
invokeCallbackAfterFiveSeconds(() => double(3));
// ^ Will log 6 to the console after a five second delay
//Passing in a function invocation below...
invokeCallbackAfterFiveSeconds(double(4));
// ^ Will log 8 to the console immediately, then do nothing else.