web-dev-qa-db-ja.com

何も返さないreturnステートメントを使用する利点はありますか?

私はオープンソースプロジェクトから拾い上げた大きなjavascriptドキュメントをリファクタリングしています。多くの関数は一貫性のないreturnステートメントを使用します。ここに私が言っていることの簡単な例を示します:

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

関数がブール値を返すこともあれば、文字列などを返すこともあります。通常、それらは、条件内の単純なreturn;ステートメントと一貫性なくペアになっています。

問題は、コードが複雑であることです。多数の一意のRegExマッチを使用し、DOMノードをオンザフライで作成および破棄するパーサーです。上記の例では、return;ステートメントをreturn false;に変更できることが予備テストで示されていますが、かなり後になるまで、スクリプトにマイナスの影響(つまり、一部の機能が動作しなくなった)があったことを理解できないかもしれません。

私の質問:空白のreturnステートメントを使用する利点はありますか?これは意図的にこのようにコーディングされているのでしょうか、それとも単に怠け者だったのでしょうか?それらをすべてreturn false;またはreturn null;に変更できますか、またはすべての呼び出しを調べて、それらの関数の結果で何をしているかを調べる必要がありますか?

40
Stephen

値なしでreturnを使用すると、値undefinedが返されます。

値がブール値として評価される場合、undefinedfalseとして機能しますが、たとえば値をfalseと比較すると、異なる動作が得られます。

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

したがって、コードは論理的にtrueまたはfalseではなくtrueまたはundefinedを返す必要がありますが、単にreturn;からreturn false;戻り値の使用方法をチェックせずに。

46
Guffa

「ブランクreturn」ステートメントを使用して、呼び出し元の関数に制御を戻す(または何らかの理由で関数の実行を停止する-例:検証など)ことができます。ほとんどの場合、空のreturnステートメントを使用するのは、何らかの検証を行うときです。ただし、関数の実行が停止された理由について何らかのインジケータを設定することは重要です。たとえば、エラーメッセージでDIV要素の「innerText」プロパティを設定します。

上記のコードでは、検証のように見えます。すべてがうまくいった場合、関数は「true」を返します。呼び出し元の関数は戻り値を解析し、それが「true」の場合、ステートメントの次のステップ(呼び出し元の関数内)が実行されるようです。

上記の例では、空の戻り値の代わりに「false」を返すことをお勧めします。そうすれば、他のプログラマーがすべてを統一し、生活を楽にすることができます。

このような不整合を修正できます。ただし、すべての変更を徹底的にテストしてください。コードに加えた各変更をテストすることをお勧めしますが、それがどんなに小さくてもかまいません。

18
Josh

ここで失われる可能性があるのは(例では直接ではありません)、トライステートオブジェクトを持つことができるということです:

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

これらの戻り値:

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

注:この例では、nullはfalseを返しますmyfunc(null);

8

関数を変更すると、return;およびreturn false;さまざまなデータ型を出力します。

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

return;return undefined;にはまったく違いはありません。両方の関数を呼び出した結果、値undefinedを受け取ります。

非常に小さいreturn vs.コードの終わりから抜け落ちますが、コードで検出できるものは何もありません。¹実行がコードの終わりから落ちた関数を呼び出すと、値は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

Unless、もちろん、何かがundefinedを隠しています。それはまだ悲しいことに可能です(しかし、喜んで、グローバルな範囲ではありません)。そのveryエッジの効いたEdgeの場合、違いがあります:

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

¹returnを使用すると、突然の完了になり、[[Call]]は値付きの通常の完了に変換されます。コードの終わりから落ちるのは、通常の完了ですspec )([[Call]]がundefined値)。ただし、これも仕様レベルの違いであり、コードで確認できるものではありません。

3
T.J. Crowder