Функции, возвращающие функцию

110

Я застрял с концепцией «Функции, возвращающие функции». Я имею в виду книгу Стояна Стефанова «Объектно-ориентированный 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()приведенными выше фрагментами?

Кафекоридор
источник
2
Вы заметите, что первый фрагмент выдает ошибку в s ();
weirdalsuperfan 09

Ответы:

122

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

Демо

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();

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

кж
источник
Фрагмент первый: var hero = {name: 'Rafaelo', sayName: function () {return hero.name; }, nayName: hero.sayName} hero.nayName (); Фрагмент второй: var hero = {name: 'Rafaelo', sayName: function () {return hero.name; }, nayName: this.sayName} hero.nayName (); Первый фрагмент дает мне правильный результат, а второй - нет. Зачем? С уважением.
Cafecorridor
thisозначает только что-то внутри тела функции, иначе это глобально. Вы говорите о this.sayNameтом, что вам нужна глобальная переменная, sayNameкоторой не существует, она не определена и поэтому не вызывается.
kzh 03
8
Меня смутила функция d () (); сначала, но потом понял, что first () вызывает d, а second () вызывает возвращаемое значение d, которым является e.
skud
1
Спустя восемь лет это актуально до сих пор!
Брэд Вандербуш
45

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

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

Вызов функции с помощью ()в операторе return выполняет функцию и возвращает любое значение, возвращенное функцией. Это похоже на вызов 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;
Майкл Берковски
источник
1
Из всех ответов мне больше понравился ваш ответ своей простотой.
анар халилов
Хорошо сказано! Этот ответ очень легко понять.
AndrewSteinheiser
Спасибо за проверку бита о том, не возвращает ли функция значение undefined. Недавно я обнаружил эту путаницу: даже если функция явно возвращает null, если вы присвоите значение, возвращаемое переменной, оно будет undefined, а не null. Я предполагаю, что это вызвало много странных проблем в некоторых базах кода, потому что null и undefined не абсолютно эквивалентны с ===.
Benjamin
37

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

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

Абдо
источник
18

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

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

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

function b() {
   return 42;
}

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

Чизо
источник
4
он должен вернуться 42;)
c69 03
4

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

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

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

Vzwick
источник
Первый дает undefined. Означает ли это, что return b () совершенно бесполезен? Кроме того, во втором фрагменте функция b является частной. Как же тогда мы можем получить доступ к ссылке вне функции? Если возможно, предоставьте мне ссылку, которая четко объясняет эту концепцию. Спасибо!
Cafecorridor
Я получил ответ на первый. верните 1 + 2 в функции b (), а typeof покажет число. Спасибо.
Cafecorridor
Рад, что ты это понял! Что касается частной функции: во втором примере она не совсем приватная, поскольку вы ее уже вернули. Фактически, он назначается s. Попробуйте return thisвместо того, чтобы return bs.b()Тогда вы сможете сделать это ;)
vzwick
Я обязательно попробую. Еще не достиг этой концепции в Javascript. Может, через пару дней. Спасибо! :)
Cafecorridor 02
функция а () {предупреждение ("А!"); функция b () {предупреждение ("B!"); } return b; } var s = a (); удалить; s (); ---- конец ---- Является ли концепция ссылки в Javascript такой же, как в Java? Здесь я удалил функцию a (), но вызов s () выполняет b (). Итак, могу ли я сказать, что s содержит копию b и не указывает на b (), определенный в a ()?
Cafecorridor
2

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

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

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

return b;

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

return b();

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

Франческо Белладонна
источник
Во втором фрагменте функция b является частной. Как же тогда мы можем получить доступ к ссылке вне функции? Есть ли правила, регулирующие то же самое?
Cafecorridor
Объекты в JavaScript (включая функции) больше не являются частными, если вы ими поделитесь.
kzh 03
@Cafecorridor: если частная функция возвращается чем-то (общедоступная функция) или назначается общедоступной переменной (ну, переменной, доступной для приложения), вы можете легко выполнить yourvariable (); , в противном случае присвойте функцию, возвращаемую переменной, и снова выполните yourvariable ();
Франческо Белладонна,
2

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

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!" 
Шаз
источник
-1

Первый фрагмент:

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

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

    return b(); //return nothing here as b not defined a return value
}

var s = a(); //s got nothing assigned as b() and thus a() return nothing.
alert('break');
s(); // s equals nothing so nothing will be executed, JavaScript interpreter will complain

оператор 'b ()' означает выполнение функции с именем 'b', которая отображает диалоговое окно с текстом 'B!'

оператор return b (); означает выполнить функцию с именем 'b' и затем вернуть то, что возвращает функция 'b'. но 'b' ничего не возвращает, тогда и этот оператор 'return b ()' ничего не возвращает. Если b () возвращает число, то return b () также является числом.

Теперь 's' присваивается значение того, что возвращает 'a ()', которое возвращает 'b ()', что является ничем, поэтому 's' - это ничто (в JavaScript это действительно вещь, это 'undefined'. Итак, когда вы просите JavaScript интерпретировать, какой тип данных представляет собой 's', интерпретатор JavaScript сообщит вам, что 's' является неопределенным.) Поскольку 's' является неопределенным, когда вы запрашиваете JavaScript для выполнения этого оператора 's ()', вы просите JavaScript выполнить функцию с именем 's', но 's' здесь означает 'undefined', а не функцию, поэтому JavaScript будет жаловаться: "эй, s не функция, я не знаю, как чтобы сделать с этим s ", то сообщение об ошибке" Uncaught TypeError: s is not a function "будет отображаться с помощью JavaScript (проверено в Firefox и Chrome)


Фрагмент два

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

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

    return b; //return pointer to function b here
}

var s = a();  //s get the value of pointer to b
alert('break');
s(); // b() function is executed

теперь функция 'a' возвращает указатель / псевдоним функции с именем 'b'. поэтому при выполнении 's = a ()' 's' получит значение, указывающее на b, то есть 's' теперь является псевдонимом 'b', вызов 's' равен вызову 'b'. ie 's' теперь функция. Execute 's ()' означает запуск функции 'b' (то же самое, что выполнение 'b ()'), диалоговое окно, показывающее 'B!' появится (т. е. выполнение оператора 'alert (' B! '); в функции' b ')

Генри пилот за работой
источник
-2

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

Работа с 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качестве аргументов.

Жильвинас
источник