¿Hay algún beneficio en usar una declaración de devolución que no devuelve nada?

6 minutos de lectura

Avatar de usuario de Stephen
Esteban

Estoy refactorizando un gran documento de javascript que recogí de un proyecto de código abierto. Varias funciones usan declaraciones de retorno inconsistentes. He aquí un ejemplo simple de lo que quiero decir:

var func = function(param) {
    if (!param) {
        return;
    }
    // do stuff
    return true;
}

A veces las funciones devuelven booleanos, a veces cadenas u otras cosas. Por lo general, se emparejan de manera inconsistente con un simple return; declaración dentro de un condicional.

El problema es que el código es complejo. Es un analizador que usa una multitud de coincidencias RegEx únicas, crea y destruye nodos DOM sobre la marcha, etc. Las pruebas preliminares muestran que, en el ejemplo anterior, podría cambiar el return; declaración para convertirse return false;pero me preocupa no darme cuenta de que tuvo un impacto negativo (es decir, alguna función dejó de funcionar) en el script hasta mucho más tarde.

Entonces, mis preguntas: ¿Hay algún beneficio en usar una declaración de devolución en blanco? ¿Podría haber sido codificado intencionalmente de esta manera o fue simplemente perezoso? ¿Puedo cambiarlos todos a return false;o return null; ¿O necesito investigar cada llamada y averiguar qué están haciendo con los resultados de esas funciones?

  • Encuentro que me detengo a pensar menos durante los ciclos de mantenimiento si devuelvo los lógicos verdaderos o falsos explícitamente, pero como otros notan, aseguro el uso funcional antes de los cambios generales.

    –Mark Schultheiss

    15 de septiembre de 2010 a las 12:29

Avatar de usuario de Guffa
Guffa

Usando return sin un valor devolverá el valor undefined.

Si el valor se evalúa como booleano, undefined funcionará como falsepero si el valor, por ejemplo, se compara con falseobtendrá un comportamiento diferente:

var x; // x is undefined
alert(x); // shows "undefined"
alert(!x); // shows "true"
alert(x==false); // shows "false"

Entonces, mientras que el código debería devolver lógicamente true o falseno true o undefinedno puedes simplemente cambiar return; a return false; sin comprobar cómo se utiliza el valor de retorno.

  • @Stephen Tenga en cuenta que esto no significa que pueda cambiarlo a return undefined; ya que eso significará devolver la variable global indefinida, que hasta los navegadores más recientes podría ser cualquier cosa.

    – Pablo

    6 de enero de 2012 a las 20:33

  • @usuario1: Soy consciente de que el undefined “constante” no es realmente constante (incluso escribí en un blog al respecto), pero no sabía que esto cambiaría. ¿Ha cambiado la especificación de EcmaScript?

    – Guffa

    6 de enero de 2012 a las 21:22

  • @Guffa Sí, cambió en ECMAScript 5. Ver sección 15.1.1.3 El valor undefined del objeto global no se puede escribir. Lo mismo ocurre con los valores Infinity y NaN.

    – Pablo

    06/01/2012 a las 21:30


  • @DavidSpector: revertí tu edición. El objetivo del código no es verificar si no está definido, ya que sabemos que el valor no está definido, sino mostrar cómo funcionan las diferentes formas de verificar un valor booleano con un valor no definido.

    – Guffa

    27 de marzo de 2013 a las 18:29

Las declaraciones de “retorno en blanco” se pueden usar para transferir el control a la función de llamada (o dejar de ejecutar una función por algún motivo, por ejemplo, validaciones, etc.). En la mayoría de los casos, uso una declaración de devolución en blanco cuando estoy haciendo algún tipo de validación. Sin embargo, me propongo establecer algún indicador de por qué se detiene la ejecución de la función. Por ejemplo, establezca la propiedad “texto interior” en un elemento DIV con el mensaje de error.

En el código anterior, parece que es una validación. La función devuelve un “verdadero” si todo salió bien. Parece que la función de llamada analiza el valor de retorno, y si es “verdadero”, se ejecuta el siguiente paso de las declaraciones (en la función de llamada).

Es una buena práctica devolver “falso” en lugar de un retorno en blanco en el ejemplo anterior. De esa manera lo haces todo uniforme y facilitas la vida a otros programadores.

Podrías arreglar tales inconsistencias; sin embargo, asegúrese de probar todos los cambios a fondo. Es una buena práctica probar cada cambio que realice en el código, por pequeño que sea.

Avatar de usuario de TJ Crowder
TJ Crowder

No hay diferencia en absoluto entre return; y return undefined;. El resultado de llamar a ambas funciones es recibir el valor undefined.

(Hay una muy pequeña diferencia de nivel de especificación entre un cuerpo de función que termina con return vs. simplemente caerse al final del código, pero no es nada que pueda detectarse en el código.¹ Llamar a una función donde la ejecución cae al final del código también da como resultado el valor undefined.)

"use strict";

// Implicit return of `undefined`
function x() {
    return;
}
// Explicit return of `undefined`
function y() {
    return undefined;
}
// Execution falls off the end
function z() {
}
console.log(typeof x() === "undefined"); // true
console.log(typeof y() === "undefined"); // true
console.log(typeof z() === "undefined"); // true

A no ser quepor supuesto, algo ha ensombrecido undefined. Lo cual, lamentablemente, todavía es posible (aunque no, con mucho gusto, a nivel mundial). En eso muy Caso de borde vanguardista, hay una diferencia:

"use strict";
(function() {
    const undefined = 42;
//  ^^^^^^^^^^^^^^^---- shadowing `undefined`
    // Implicit return of `undefined`
    function x() {
        return;
    }
    // Explicit return of `undefined`
    function y() {
        return undefined;
    }
    // Execution falls off the end
    function z() {
    }
    console.log(typeof x() === "undefined"); // true, `x` returns the canonical `undefined`
    console.log(typeof y() === "undefined"); // false, `y` returns 42
    console.log(typeof z() === "undefined"); // true, `z` (effectively) returns the canonical `undefined`
})();

¹ Usando return es un terminación abrupta que [[Call]]se convierte en una finalización normal con valor. Caerse del final del código es un terminación normal (Especificaciones) (que [[Call]]asegura suministros undefined por el valor). Pero nuevamente, esta es una diferencia de nivel de especificación, no algo que se pueda observar en el código.

Avatar de usuario de Mark Schultheiss
Marcos Schultheiss

Lo que PODRÍA perderse aquí (no directamente con su ejemplo) es que luego puede tener un objeto de tres estados:

var myfunc = function(testparam) {
    if (typeof testparam === 'undefined') return;
    if (testparam) {
        return true;
    }
    else {
        return false;
    }
};

var thefirst = myfunc(true)
var thesecond = myfunc(false);
var thelast = myfunc();
alert("type:" + typeof thefirst+" value:"+thefirst);
alert("type:" + typeof thesecond+" value:"+thesecond);  
alert("type:" + typeof thelast+" value:"+thelast); 

estos regresan:

> type:boolean:true 
> type:boolean:false
> type:undefined:undefined

nota: null devolvería false en este ejemplo myfunc(null);

Avatar de usuario de Q_Mlilo
Q_Mlilo

Cambiar sus funciones en realidad alterará el código porque return; y return false; generar diferentes tipos de datos.

var test = function (x) {
    if (!x) {
        return;
    }
    else {
        return false;
    }
};

var a = test(true), b = test(false);

console.log(typeof b); // undefined
console.log(typeof a); // boolean

¿Ha sido útil esta solución?