Функції, що повертають функцію


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

Відповіді:


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яка не існує, вона не визначена, тому її не можна називати.
кж

7
Мене збентежив d () (); спочатку, але потім зрозумів, що перший () викликає d, а другий () викликає зворотне значення d, яке є e.
skud

1
Через вісім років, і це все ще актуально!
Бред Вандербуш

45

Повернення імені функції без ()повернення посилання на функцію, яку можна призначити так, як ви робили 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;

1
З усіх відповідей мені більше сподобалась ваша відповідь через її простоту.
анар халілов

Добре кажучи! Дуже легко зрозуміти цю відповідь.
AndrewSteinheiser

Дякуємо, що перевірили біт про те, якщо функція не повертає значення, виклик повертається невизначеним. Нещодавно я виявив це занепокоєння: навіть якщо функція явно повертає нуль, якщо призначити повернене значення змінній, воно буде невизначеним, а не нульовим. Я думаю, це спричинило багато дивних проблем у деяких кодових базах, тому що null та undefined не є абсолютно еквівалентними ===.
Бенджамін

37

return b(); викликає функцію b () і повертає її результат.

return b; повертає посилання на функцію b, яку ви можете зберігати у змінній для виклику пізніше.


17

Повернення b - це повернення об'єкта функції. У Javascript функції - це просто об'єкти, як і будь-який інший об’єкт. Якщо ви вважаєте, що це не корисно, просто замініть слово "об'єкт" на "річ". Ви можете повернути будь-який об’єкт з функції. Ви можете повернути справжнє / хибне значення. Ціле число (1,2,3,4 ...). Ви можете повернути рядок. Ви можете повернути складний об'єкт з декількома властивостями. І ви можете повернути функцію. функція - це просто річ.

У вашому випадку повернення bповертає річ, річ є функцією дзвінка. Повернення b()повертає значення, повернене функцією дзвінка.

Розглянемо цей код:

function b() {
   return 42;
}

Використовуючи наведене визначення, return b();повертає значення 42. З іншого боку, return b;повертає функцію, яка сама повертає значення 42. Це дві різні речі.


4
воно має повернутися 42;)
c69

4

Коли ви повернетесь b, це лише посилання на функцію b, але наразі вона не виконується.

Коли ви повернетеся b(), ви виконання функції і повертає його значення.

Спробуйте alertING typeof(s)в ваших прикладах. Знімок b дасть вам «функцію». Що буде фрагмент подарунка?


Перший дає "невизначений". Чи означає, що повернення b () абсолютно марно? Також у другому фрагменті функція b є приватною. Як тоді ми маємо доступ до посилання поза функцією? Надайте, будь ласка, посилання, яке пояснює це поняття, якщо можливо. Дякую!
Cafecorridor

Я отримав відповідь на перший. поверніть 1 + 2 у функції b (), а typeof показує число. Дякую.
Cafecorridor

Радий, що ви зрозуміли це! Що стосується приватної функції: насправді вона не є приватною у другому прикладі, оскільки ви її вже повернули. Насправді це привласнюється s. Спробуйте return thisзамість цього return bхоч… Ви зможете це зробити s.b();)
vzwick

Я спробую це точно. Ще не досягли цієї концепції в Javascript. Може, через пару днів. Дякую! :)
Cafecorridor

функція a () {сигнал ("A!"); функція b () {сигнал ("B!"); } повернути b; } var s = a (); видалити a; s (); ---- end ---- Чи поняття посилання в Javascript таке ж, як у Java? Тут я видалив функцію a (), і все ж виклик s () виконує b (). Тож чи можу я сказати, що s містить копію b і не вказує на b (), визначене в ()?
Cafecorridor

2

Уявіть функцію як тип, як int. Ви можете повернути вставки у функції. Ви також можете повернути функції, вони є об'єктом типу "функція".

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

пропускаючи дужки! Тому що без дужок функція не буде виконуватися! Так:

return b;

Поверне функцію (уявіть її, як якщо ви повертаєте номер), тоді як:

return b();

Спочатку виконується функція, потім повертається значення, отримане її виконанням, велика різниця!


У другому фрагменті функція b є приватною. Як тоді ми маємо доступ до посилання поза функцією? Чи існують правила, що регулюють те саме?
Cafecorridor

Об'єкти в JavaScript (сюди входять функції) більше не є приватними, якщо ви ними надаєте спільний доступ.
кж

@Cafecorridor: Якщо приватна функція повертається чимось (загальнодоступною функцією) або призначається загальнодоступній змінній (ну, змінна, доступна для додатків), ви можете легко зробити свою змінну ();, в іншому випадку призначте функцію, повернуту змінній, і зробіть знову свою змінну ();
Франческо Беладонна

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 ()' return, що повертає 'b ()', що є нічим, так 's' є нічим (в JavaScript це фактично річ, це 'undefined'. Отже коли ви попросите JavaScript інтерпретувати, що таке тип даних "s", інтерпретатор JavaScript скаже, що "s" є невизначеним.) Як "s" є невизначеним, коли ви попросите JavaScript виконати цей оператор 's ()', ви просите JavaScript виконати функцію, названу як 's', але 's' тут - 'undefined', а не функція, тому JavaScript буде скаржитися: "hey, s - це не функція, я не знаю як робити з цим s ", тоді повідомлення про помилку" Uncaught TypeError: s не є функцією "буде показано 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'. тому, коли Execute 's = a ()', 's' отримає значення, що вказує на b, тобто 's' є псевдонімом 'b' зараз, виклик 's' дорівнює виклику 'b'. тобто 's' - це функція зараз. Виконати '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 );

Але що робити, якщо вам потрібно додати якусь обгортку, оброблювач помилок або smth?

Потім ви викликаєте свою функцію із обгортки.

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аргументи.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.