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


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.