Функции, которые возвращают функцию - PullRequest
91 голосов
/ 03 октября 2011

Я застрял с этой концепцией «Функции, которые возвращают функции».Я имею в виду книгу Стояна Стефанова «Объектно-ориентированный JavaScript».

Фрагмент первый:

    function a() {
      
        alert('A!');
    
        function b(){
            alert('B!'); 
        }
    
        return b();
    }
    
    var s = a();
    alert('break');
    s();

Вывод:

A!
B!
break

Фрагмент два

function a() {
  
    alert('A!');

    function b(){
        alert('B!'); 
    }

    return b;
}

var s = a();
alert('break');
s();
Вывод:
A!
break
B!

Может кто-нибудь подсказать разницу между возвратом b и b() в приведенных выше фрагментах?

Ответы [ 8 ]

101 голосов
/ 03 октября 2011

Присваивание переменной функции (без скобок) копирует ссылку на функцию.Поставив круглые скобки в конце имени функции, вызывает функцию, возвращая возвращаемое значение функции.

Демо

function a() {
    alert('A');
}
//alerts 'A', returns undefined

function b() {
    alert('B');
    return a;
}
//alerts 'B', returns function a

function c() {
    alert('C');
    return a();
}
//alerts 'C', alerts 'A', returns undefined

alert("Function 'a' returns " + a());
alert("Function 'b' returns " + b());
alert("Function 'c' returns " + c());

В вашем примере вы такжеопределение функций внутри функции.Например:

function d() {
    function e() {
        alert('E');
    }
    return e;
}
d()();
//alerts 'E'

Функция по-прежнему вызывается.Это все еще существует.Это используется в JavaScript все время.Функции могут передаваться вокруг просто , как и другие значения.Рассмотрим следующее:

function counter() {
    var count = 0;
    return function() {
        alert(count++);
    }
}
var count = counter();
count();
count();
count();

Функция count может хранить переменные, которые были определены вне ее.Это называется закрытием.Он также часто используется в JavaScript.

43 голосов
/ 03 октября 2011

Возвращение имени функции без () возвращает ссылку на функцию, которую можно назначить, как вы сделали с var s = a().s теперь содержит ссылку на функцию b(), а вызов s() функционально эквивалентен вызову b().

// Return a reference to the function b().
// In your example, the reference is assigned to var s
return b;

. При вызове функции с () в операторе возврата выполняетсяфункция, и возвращает любое значение, которое было возвращено функцией.Это похоже на вызов var x = b();, но вместо присвоения возвращаемого значения b() вы возвращаете его из вызывающей функции a().Если сама функция b() не возвращает значение, вызов возвращает undefined после выполнения любой другой работы с помощью b().

// Execute function b() and return its value
return b();
// If b() has no return value, this is equivalent to calling b(), followed by
// return undefined;
30 голосов
/ 03 октября 2011

return b(); вызывает функцию b () и возвращает ее результат.

return b; возвращает ссылку на функцию b, которую можно сохранить в переменной для последующего вызова.

15 голосов
/ 03 октября 2011

Returning b возвращает функциональный объект.В Javascript функции - это просто объекты, как и любой другой объект.Если вам это не поможет, просто замените слово «объект» на «вещь».Вы можете вернуть любой объект из функции.Вы можете вернуть значение true / false.Целое число (1,2,3,4 ...).Вы можете вернуть строку.Вы можете вернуть сложный объект с несколькими свойствами.И вы можете вернуть функцию.функция это просто вещь.

В вашем случае возвращение b возвращает вещь, вещь является вызываемой функцией.Возвращение b() возвращает значение, возвращаемое вызываемой функцией.

Рассмотрим этот код:

function b() {
   return 42;
}

Используя приведенное выше определение, return b(); возвращает значение 42. С другой стороны, return b; возвращает функцию, которая сама возвращает значение 42Это две разные вещи.

3 голосов
/ 03 октября 2011

Когда вы возвращаете b, это просто ссылка на функцию b, но в данный момент она не выполняется.

Когда вы возвращаете b(), вы выполняете функцию и возвращаете ее значение.

Попробуйте alert ing typeof(s) в ваших примерах. Фрагмент б даст вам «функцию». Что вам даст фрагмент?

2 голосов
/ 03 октября 2011

Создать переменную :

var thing1 = undefined;

Объявить Функция :

function something1 () {
    return "Hi there, I'm number 1!";
}

Оповещение о значении из thing1 (наша первая переменная):

alert(thing1); // Outputs: "undefined".

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

thing1 = something1;

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

thing1 = something1(); // Value of thing1: "Hi there, I'm number 1!" 
2 голосов
/ 03 октября 2011

Представьте функцию как тип, например, int. Вы можете вернуть целые числа в функцию. Вы также можете возвращать функции, они являются объектами типа «функция».

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

, опуская скобки! Потому что без скобок функция не будет выполнена! Итак:

return b;

Вернет «функцию» (представьте, что если вы возвращаете число), тогда как:

return b();

Сначала выполняется функция , затем возвращает значение, полученное при его выполнении, это большая разница!

0 голосов
/ 15 марта 2018

Это очень полезно в реальной жизни.

Работа с Express.js

Итак, ваш обычный маршрут express выглядит следующим образом:

function itWorksHandler( req, res, next ) {
  res.send("It works!");
}

router.get("/check/works", itWorksHandler );

Но что, если вам нужно добавить какую-нибудь оболочку, обработчик ошибок или что-то еще?

Затем вы вызываете свою функцию из оболочки.

function loggingWrapper( req, res, next, yourFunction ) {
  try {
    yourFunction( req, res );
  } catch ( err ) {
    console.error( err );
    next( err );
  }
}

router.get("/check/works", function( req, res, next ) {
  loggingWrapper( req, res, next, itWorksHandler );
});

Выглядит сложно?Хорошо, как об этом:

function function loggingWrapper( yourFunction ) => ( req, res, next ) {
  try {
    yourFunction( req, res, next );
  } catch ( err ) {
    console.error( err );
    next( err );
  }
}

router.get("/check/works", loggingWrapper( itWorksHandler ) );

В конце вы видите, что вы передаете функцию loggingWrapper, имеющую один аргумент в качестве другой функции itWorksHandler, и ваш loggingWrapper возвращает новую функциюкоторый принимает req, res, next в качестве аргументов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...