Почему обратные вызовы должны быть функцией? - PullRequest
0 голосов
/ 19 мая 2019

Я продолжаю видеть:

() => execute code

вместо

execute code 

в обратных вызовах. Я не передаю никаких параметров, так почему () => выполнение кода работает, а выполнение кода - нет? Разве это не одно и то же, поскольку функция просто представляет несколько строк кода? Я вижу похожие вещи и в других языках, например в Java, где используется лямбда

Спасибо.

Ответы [ 5 ]

4 голосов
/ 19 мая 2019

Обратные вызовы используются, потому что функция должна быть вызвана - код должен выполняться - в какой-то неопределенной точке в будущем.Простое выполнение кода в JavaScript всегда будет выполнять его немедленно.Это не полезно, если вам нужно выполнить какое-то асинхронное задание, а затем что-то сделать.

Например, setTimeout() принимает обратный вызов, потому что ему нужно подождать, а затем делают что-то:

//In  about 1500 ms setTimeout will call this ()=>{} function
setTimeout(() => {
  console.log("finished")
}, 1500)

Возможность передавать такую ​​функцию очень гибкая, поскольку функция также может принимать аргументы и возвращать значения, которые могут быть определены во время вызова функции.Это было бы намного сложнее или было бы невозможно, если бы код не был организован в функции.

Если я просто передал выражение напрямую, оно выполняется немедленно:

// console.log runs immediately, there's not way to defer it.
    setTimeout( console.log("finished")
    , 1000)

Таким образом, функция не просто представляет некоторый код, она представляет действие, которое можно назвать .Он может быть вызван вами или другой функцией, такой как setTimeout или HTTP-запросом в определенное время.

1 голос
/ 19 мая 2019

Разница в том, что () => 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 не имеет возвращаемого значения) доступно в теле функции, в которую оно передается.

* * 1 022 Пример: * 1 023 *
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.

1 голос
/ 19 мая 2019

То, что вы видите, это функция в Javascript, называемая функцией стрелки, и может быть записана следующим образом:

Одна строка, если возвращена одна операция:

const f = (a,b) => return a+b;

Или блок строк для дополнительных операций:

const f = (a,b) => { c = a + b; return c};
0 голосов
/ 19 мая 2019

Потому что если вы сделаете это так, как вы предлагаете, код будет выполнен немедленно; т.е. когда вы делаете звонок.

Вы должны понимать, что

() -> doSomething()

и

doSomething()

означают разные вещи (делай это позже, а не делай сейчас) и оценивай разные значения. У них даже нет того же типа. Предполагая, что doSomething() возвращает SomeType:

  • лямбда-выражение оценивается как объект, совместимый с Supplier<SomeType> и
  • вызов оценивается как объект, совместимый с SomeType.

Полагаю, вы считаете, что было бы неплохо, если бы вы могли использовать один и тот же синтаксис для обоих случаев, и чтобы компилятор определил правильное значение в зависимости от контекста. Есть две проблемы с этим:

  1. Это усложнит понимание кода. Когда вы читаете чей-то код, вам нужно знать, ожидал ли каждый параметр каждого выражения что-либо с семантикой немедленной оценки (например, вызовом метода) или семантикой отложенной оценки (например, лямбда-выражением).

    Еще в 1960-х годах они фактически разработали и внедрили язык программирования, который работал следующим образом. (Посмотрите на Алгол-60 и «позвоните по имени».) Это была ошибка. Программы Algol-60, использующие вызов по имени , трудны для понимания. AFAIK, с тех пор ошибка не повторялась ни на одном из основных языков программирования.

  2. Вам все равно нужно будет объявить, имел ли параметр семантику немедленной или ленивой оценки. Я думаю, что было бы невозможно сделать вывод, что требовалось в объявлении метода.

0 голосов
/ 19 мая 2019

Функция необходима для того, чтобы знать, что код не должен выполняться немедленно.
Если вы используете

myFunction(myArg, window.location.href='https://www.stackoverflow.com');

Вместо

myFunction(myArg, () => {   
    window.location.href='https://www.stackoverflow.com';
});

, языкне в состоянии знать, что код должен быть выполнен позже в качестве обратного вызова в первом случае.Как следствие, он выполняется, как только вызывается метод, который приводит к булевому переданию вместо функции к обратному вызову.И в этом сценарии вместо переключения на stackoverflow.com после выполнения в качестве обратного вызова страница будет открыта немедленно, даже если вызываемая функция не запустилась полностью.на более позднем этапе, вызвав его.

Часто параметр с результатами передается обратному вызову, чтобы разрешить их обработку.

...