Funciones que devuelven una función

110

Estoy atascado con este concepto de 'Funciones que devuelven funciones'. Me refiero al libro "JavaScript orientado a objetos" de Stoyan Stefanov.

Fragmento uno:

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

Salida:

A!
B!
break

Fragmento dos

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

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

    return b;
}

var s = a();
alert('break');
s();
Salida:

A!
break
B!

¿Alguien puede decirme la diferencia entre regresar by b()en los fragmentos anteriores?

Cafecorridor
fuente
2
Notará que el primer fragmento da un error en s ();
weirdalsuperfan

Respuestas:

122

Asignar una variable a una función (sin paréntesis) copia la referencia a la función. Poniendo el paréntesis al final del nombre de una función, llama a la función, devolviendo el valor de retorno de la función.

Manifestación

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

En su ejemplo, también está definiendo funciones dentro de una función. Como:

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

La función aún se puede llamar. Todavía existe. Esto se usa en JavaScript todo el tiempo. Las funciones se pueden transferir simplemente como otros valores. Considera lo siguiente:

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

La función count puede mantener las variables que se definieron fuera de ella. A esto se le llama cierre. También se usa mucho en JavaScript.

kzh
fuente
Fragmento uno: var hero = {nombre: 'Rafaelo', sayName: function () {return hero.name; }, nayName: hero.sayName} hero.nayName (); Fragmento dos: var hero = {nombre: 'Rafaelo', sayName: function () {return hero.name; }, nayName: this.sayName} hero.nayName (); El primer fragmento me da el resultado correcto mientras que el segundo no. ¿Por qué? Saludos.
Cafecorridor
thissolo significa algo dentro de un cuerpo de función, de lo contrario es global. Lo que está diciendo this.sayNamees que desea la variable global sayNameque no existe, no está definida, por lo que no se puede llamar.
2011
7
Estaba confundido por la d () (); al principio, pero luego se dio cuenta de que el primer () llama a d y el segundo () llama al valor de retorno de d, que es e.
skud
1
¡Ocho años después y esto sigue siendo relevante!
Brad Vanderbush
45

Devolver el nombre de la función sin ()devolver una referencia a la función, que se puede asignar como lo hizo con var s = a(). sahora contiene una referencia a la función b(), y llamar s()es funcionalmente equivalente a llamar b().

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

Llamar a la función con ()una declaración de retorno ejecuta la función y devuelve cualquier valor devuelto por la función. Es similar a llamar var x = b();, pero en lugar de asignar el valor de b()retorno, lo devuelve de la función de llamada a(). Si la función en b()sí no devuelve un valor, la llamada regresa undefineddespués de cualquier otro trabajo realizado por 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;
Michael Berkowski
fuente
1
De todas las respuestas, me gustó más tu respuesta por su sencillez.
anar khalilov
¡Así poner! Muy fácil de entender esta respuesta.
AndrewSteinheiser
Gracias por validar el bit sobre si la función no devuelve un valor, la llamada devuelve indefinido. Descubrí esto recientemente: incluso si la función devuelve nulo explícitamente, si asigna el valor devuelto a una variable, será indefinido, no nulo. Me imagino que esto causó muchos problemas extraños en algunas bases de código, porque nulo e indefinido no son absolutamente equivalentes con ===.
Benjamin
37

return b(); llama a la función b () y devuelve su resultado.

return b; devuelve una referencia a la función b, que puede almacenar en una variable para llamar más tarde.

Abdo
fuente
17

Devolver bes devolver un objeto de función. En Javascript, las funciones son solo objetos, como cualquier otro objeto. Si no lo encuentra útil, reemplace la palabra "objeto" por "cosa". Puede devolver cualquier objeto de una función. Puede devolver un valor verdadero / falso. Un número entero (1,2,3,4 ...). Puede devolver una cadena. Puede devolver un objeto complejo con varias propiedades. Y puede devolver una función. una función es solo una cosa.

En su caso, devolver bdevuelve la cosa, la cosa es una función invocable. Devolver b()devuelve el valor devuelto por la función invocable.

Considere este código:

function b() {
   return 42;
}

Usando la definición anterior, return b();devuelve el valor 42. Por otro lado, return b;devuelve una función, que en sí misma devuelve el valor de 42. Son dos cosas diferentes.

Cheeso
fuente
4
debería regresar 42;)
c69
4

Cuando regresa b, es solo una referencia a la función b, pero no se está ejecutando en este momento.

Cuando regresa b(), está ejecutando la función y devolviendo su valor.

Trate alerting typeof(s)en sus ejemplos. El fragmento b le dará "función". ¿Qué te dará un fragmento?

vzwick
fuente
El primero da 'indefinido'. ¿Significa que return b () es completamente inútil? Además, en el segundo fragmento, la función b es privada. Entonces, ¿cómo podemos acceder a la referencia fuera de la función? Si es posible, proporcione un enlace que explique este concepto claramente. ¡Gracias!
Cafecorridor
Recibí la respuesta a la primera. devuelve 1 + 2 en la función b () y el tipo de muestra el número. Gracias.
Cafecorridor
¡Me alegra que lo hayas descubierto! En cuanto a la función privada: no es realmente privada en el segundo ejemplo, ya que ya la devolvió. De hecho, se le asigna s. Intente en return thislugar de return baunque ... Podrá hacerlo s.b()entonces;)
vzwick
Lo probaré seguro. Aún no he alcanzado este concepto en Javascript. Quizás en un par de días. ¡Gracias! :)
Cafecorridor
función a () {alerta ("A!"); función b () {alerta ("B!"); } return b; } var s = a (); eliminar un; s (); ---- fin ---- ¿El concepto de referencia en Javascript es el mismo que en Java? Aquí borré la función a () y, sin embargo, una llamada a s () ejecuta b (). Entonces, ¿puedo decir que s contiene una copia de by no apunta a b () definido en a ()?
Cafecorridor
2

Imagina la función como un tipo, como un int. Puede devolver ints en una función. También puede devolver funciones, son objeto de tipo "función".

Ahora el problema de sintaxis: debido a que las funciones devuelven valores, ¿cómo se puede devolver una función y no su valor de retorno?

omitiendo los corchetes! ¡Porque sin corchetes, la función no se ejecutará! Entonces:

return b;

Devolverá la "función" (imagínelo como si estuviera devolviendo un número), mientras que:

return b();

Primero ejecuta la función y luego devuelve el valor obtenido al ejecutarla, ¡es una gran diferencia!

Francesco Belladonna
fuente
En el segundo fragmento, la función b es privada. Entonces, ¿cómo podemos acceder a la referencia fuera de la función? ¿Existen reglas que rijan lo mismo?
Cafecorridor
Los objetos en JavaScript (esto incluye funciones) ya no son privados si los comparte.
2011
@Cafecorridor: Si la función privada es devuelta por algo (una función pública) o está asignada a una variable pública (bueno, una variable accesible a la aplicación), puede hacer fácilmente su variable (); , de lo contrario, asigne la función devuelta a una variable y vuelva a hacer yourvariable ();
Francesco Belladonna
2

Crea una variable :

var thing1 = undefined;

Declarar una función :

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

Alerta el valor de thing1(nuestra primera variable):

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

Ahora, si quisiéramos thing1ser una referencia a la función something1, lo que significa que sería lo mismo que nuestra función creada, haríamos:

thing1 = something1;

Sin embargo, si queremos el return valor de la función, debemos asignarle el valor de retorno de la función ejecutada. Ejecuta la función usando paréntesis:

thing1 = something1(); // Value of thing1: "Hi there, I'm number 1!" 
Shaz
fuente
-1

Fragmento uno:

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

la declaración 'b ()' significa ejecutar la función llamada 'b' que muestra un cuadro de diálogo con el texto 'B!'

la declaración 'return b ();' significa ejecutar una función llamada 'b' y luego devolver la función que devuelve 'b'. pero 'b' no devuelve nada, entonces esta declaración 'return b ()' tampoco devuelve nada. Si b () devuelve un número, entonces 'return b ()' también es un número.

Ahora a 's' se le asigna el valor de lo que devuelve 'a ()', que devuelve 'b ()', que no es nada, entonces 's' no es nada (en JavaScript es una cosa en realidad, es un 'indefinido'. cuando le pide a JavaScript que interprete qué tipo de datos es la 's', el intérprete de JavaScript le dirá que 's' es indefinido.) Como 's' es indefinido, cuando le pide a JavaScript que ejecute esta declaración 's ()', le está pidiendo a JavaScript que ejecute una función llamada 's', pero 's' aquí es un 'indefinido', no una función, por lo que JavaScript se quejará, "oye, s no es una función, no sé cómo que ver con este s ", JavaScript mostrará un mensaje de error" Uncaught TypeError: s no es una función "(probado en Firefox y Chrome)


Fragmento dos

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

ahora, la función 'a' devuelve un puntero / alias a una función llamada 'b'. así que cuando se ejecuta 's = a ()', 's' obtendrá un valor que apunta a b, es decir, 's' es un alias de 'b' ahora, llamar a 's' es igual a llamar a 'b'. es decir, 's' es una función ahora. Ejecutar 's ()' significa ejecutar la función 'b' (lo mismo que ejecutar 'b ()'), un cuadro de diálogo que muestra 'B!' aparecerá (es decir, ejecutando la instrucción 'alert (' B! '); en la función' b ')

Henry piloto en el trabajo
fuente
-2

Esto es muy útil en la vida real.

Trabajando con Express.js

Entonces, su expressruta regular se ve así:

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

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

Pero, ¿qué sucede si necesita agregar algún contenedor, controlador de errores o algo?

Luego invocas tu función desde un contenedor.

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

¿Parece complicado? Bueno, ¿qué tal esto?

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

Vea al final que está pasando una función que loggingWrappertiene un argumento como otra función itWorksHandler, y loggingWrapperdevuelve una nueva función que toma req, res, nextcomo argumentos.

Zilvinas
fuente