web-dev-qa-db-fra.com

Y a-t-il un avantage à utiliser une déclaration de retour qui ne renvoie rien?

Je refactorise un grand document javascript que j'ai récupéré d'un projet open source. Un certain nombre de fonctions utilisent des instructions de retour incohérentes. Voici un exemple simple de ce que je veux dire:

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

Parfois, les fonctions renvoient un booléen, parfois des chaînes ou d'autres choses. Ils sont généralement associés de manière incohérente à un simple return; instruction à l'intérieur d'un conditionnel.

Le problème est que le code est complexe. Il s'agit d'un analyseur qui utilise une multitude de correspondances RegEx uniques, crée et détruit des nœuds DOM à la volée, etc. Des tests préliminaires montrent que, dans l'exemple ci-dessus, je pourrais changer le return; instruction pour devenir return false;, mais je crains de ne pas m'être rendu compte que cela a eu un impact négatif (c'est-à-dire qu'une fonctionnalité a cessé de fonctionner) sur le script bien plus tard.

Donc, mes questions: Y a-t-il un avantage à utiliser une déclaration de retour vierge? Cela aurait-il pu être codé intentionnellement de cette façon ou était-ce simplement paresseux? Puis-je les changer tous en return false;, ou return null; ou ai-je besoin de fouiller chaque appel et de savoir ce qu'ils font avec les résultats de ces fonctions?

40
Stephen

L'utilisation de return sans valeur retournera la valeur undefined.

Si la valeur est évaluée comme un booléen, undefined fonctionnera comme false, mais si la valeur par exemple est comparée à false, vous obtiendrez un comportement différent:

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

Ainsi, alors que le code doit logiquement renvoyer true ou false, pas true ou undefined, vous ne pouvez pas simplement modifier return; à return false; sans vérifier comment la valeur de retour est utilisée.

46
Guffa

Les instructions "retour vierge" peuvent être utilisées pour retransférer le contrôle à la fonction appelante (ou arrêter l'exécution d'une fonction pour une raison quelconque - ex: validations, etc.). Dans la plupart des cas, j'utilise une déclaration de retour vide lorsque je fais une sorte de validation. Cependant, je tiens à définir un indicateur pour expliquer pourquoi l'exécution de la fonction est arrêtée. Par exemple, définissez la propriété "innerText" sur un élément DIV avec le message d'erreur.

Dans le code ci-dessus, il semble que ce soit une validation. La fonction renvoie un "vrai" si tout s'est bien passé. Il semble que la fonction appelante analyse la valeur de retour, et si elle est "vraie", l'étape suivante des instructions (dans la fonction appelante) est exécutée.

Il est recommandé de renvoyer "false" au lieu d'un retour vide dans l'exemple ci-dessus. De cette façon, vous rendez tout uniforme et simplifiez la vie des autres programmeurs.

Vous pouvez corriger de telles incohérences; cependant, assurez-vous de tester soigneusement toutes les modifications. Il est recommandé de tester chaque modification apportée au code, aussi minime soit-elle.

18
Josh

Ce qui POURRAIT être perdu ici (pas directement avec votre exemple), c'est que vous pouvez alors avoir un objet à trois états:

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

ces retours:

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

note: null retournerait false dans cet exemple myfunc (null);

8
Mark Schultheiss

Changer vos fonctions va en fait modifier le code car return; et return false; affiche différents types de données.

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

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

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

Il n'y a aucune différence entre return; et return undefined;. Le résultat de l'appel des deux fonctions est de recevoir la valeur undefined.

(Il y a une très petite différence de niveau de spécification entre un corps de fonction qui se termine par return vs . simplement tomber la fin du code, mais ce n'est rien qui peut être détecté dans le code.¹ L'appel d'une fonction où l'exécution tombe à la fin du code entraîne également la valeur 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

À moins que , bien sûr, quelque chose ait ombragé undefined. Ce qui est malheureusement encore possible (mais pas, heureusement, à l'échelle mondiale). Dans ce cas très edgy Edge, il y a une différence:

"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`
})();

¹ L'utilisation de return est un achèvement brutal que [[Appel]] convertit en un achèvement normal avec valeur. La fin du code est un achèvement normal ( spec ) (que [[Call]] assure les fournitures undefined pour la valeur). Mais encore une fois, c'est une différence de niveau de spécification, pas quelque chose qui est observable dans le code.

3
T.J. Crowder