「return」キーワードとはどのタイプですか?


95

JavaScript関数では、オプションでreturnステートメントを使用します。キーワードです。しかし、returnそれ自体の実際のタイプは何ですか。実際に私は例を見て混乱しました:

function add(a, b) {
  return (
    console.log(a + b),
    console.log(arguments)
  );
}

add(2, 2);

出力:

4
[2, 2]

したがって、コンマ区切りの式をreturnステートメントに渡すことができます。これは機能ですか?

そしてこれから始めて、JavaScriptのすべてのキーワードが最終的には関数であると思い込んでみませんか?

このディスカッションの要旨として、小さなブログを書きました。ここで確認してください


106
JavaScriptを理解したと思ったとき、このようなことが
FP

12
大括弧は、関数を呼び出すことを意味するものではありませんvar a = (2 + 2)。例:
alexmac

12
より適切な例は、var a = (1, 2)-これがもたらすa価値を有する2(はい、カンマは数学のような演算子である起因コンマ演算子は動作方法+|、ランバダの計算において、具体的には、コンマ演算子が実装Kコンビネータなど)
slebetman

6
次に、正しい行動は、誤解を否認することであり、反対投票ではありません。
el.pescado

5
@FlorianPeschkaではありません。これは、Cフレーバー言語の標準的な動作です。
djechlin

回答:


129

しかし、「返品」自体の実際のタイプは何ですか。

タイプはありません。値ではありません。

しようとしています typeof return;ことはあなたを与えるでしょうUnexpected token return

したがって、コンマ区切りの式をreturnステートメントに渡すことができます。これは機能ですか?

いいえ、括弧関数の呼び出しに使用できますが、ここではグループ化演算子ですコンマ演算子で区切られた2つの式を含むです。

より有用なデモンストレーションは次のとおりです。

function add(a, b) {
  return (
    (a + b),
    (a - b)
  );
}

console.log(add(2, 2));

0の結果a + bが無視されて出力され(カンマ演算子のLHSにあります)、a - b返されます。


ただし、上記の例では、各式が1つずつ実行されます。あなたが述べたケースは元の質問で述べられたものとは異なると思います。私が言いたいのは、グループ演算子の優先順位が適用される場所です。
Arnab Das

3
@ArnabDas —はい、実行されreturnますが、表示されません。これは、あなたが求めていたものです。
クエンティン

@ArnabDas —「ここで言いたいのは、グループ演算子の優先順位が適用される場所です。」—もちろんグループ化演算子内。
クエンティン

11
@ArnabDas —はい。a + b副作用がなく、値が破棄されるため、目に見える効果はありません(実際には影響がないことを考えると、最適化コンパイラが削除する可能性がありますが、実際には違いはありません)。
クエンティン

1
正しい@Roman。実行されないように式を「スキップ」する唯一の方法(のような条件内を除くif)は、短絡評価です。カンマ演算子は短絡しないため、両側を評価します。その後、最後のものを返します。それが明示的に単一の文でグループ式にカンマ演算子の目的は、(文全体の通常結果の値は無視される)で、ほとんどの場合、変数の初期化に使用される:var i = 2, j = 3, k = 4;
ジェイソン

32

ここで誰も直接仕様を参照ていなかったことにちょっとショックです:

12.9 returnステートメントの構文ReturnStatement:return; return [ここにはLineTerminatorはありません]式;

意味論

ECMAScriptプログラムは、FunctionBody内にないreturnステートメントを含む場合、構文的に正しくないと見なされます。returnステートメントにより、関数は実行を停止し、呼び出し元に値を返します。Expressionが省略されている場合、戻り値は未定義です。それ以外の場合、戻り値はExpressionの値です。

ReturnStatementは次のように評価されます。

式が存在しない場合は、を返し(return, undefined, empty)ます。exprRef式を評価した結果としましょう。リターン(return, GetValue(exprRef), empty)

したがって、仕様により、例では次のようになります。

return ( GetValue(exprRef) )

どこ exprRef = console.log(a + b), console.log(arguments)

カンマ演算子の仕様によると...

意味論

プロダクション式:Expression、AssignmentExpressionは次のように評価されます。

Let lref be the result of evaluating Expression.
Call GetValue(lref).
Let rref be the result of evaluating AssignmentExpression.
Return GetValue(rref).

...すべての式が、割り当て式になるコンマリストの最後の項目まで評価されることを意味します。だからあなたのコードreturn (console.log(a + b) , console.log(arguments))

1.)の結果を出力する a + b

2.)実行するものが残っていないため、次の式を実行します。

3.)を出力しargumentsconsole.log()returnステートメントを指定していないため

4.)未定義に評価

5.)その後、呼び出し元に返されます。

したがって、正しい答えは、return型がなく、式の結果のみを返すことです。

次の質問について:

したがって、コンマ区切りの式をreturnステートメントに渡すことができます。これは機能ですか?

いいえ。JavaScriptのコンマは演算子であり、複数の式を1行に結合できるように定義されており、リストの最後にあるものの評価された式を返すように仕様で定義されています。

あなたはまだ私を信じていませんか?

<script>
alert(foo());
function foo(){
    var foo = undefined + undefined;
    console.log(foo);
    return undefined, console.log(1), 4;
}
</script>

ここでそのコードをいじって、リストの最後の値をいじってください。それは常にリストの最後の値を返します、あなたの場合それはたまたまですundefined.

最後の質問は、

そしてこれから始めて、JavaScriptのすべてのキーワードが最終的には関数であると思い込んでみませんか?

繰り返しますが、違います。 関数は、言語で非常に具体的な定義があります。この回答はすでに非常に長くなっているので、ここでは転載しません。


15

括弧で囲まれた値を返すとどうなるかをテストします。

function foo() {
    return (1, 2);
}

console.log(foo());

答えを与える2ので、値のコンマ区切りのリストはリストの最後の要素に評価されるように見えます。

かっこはここでは関係ありません。関数呼び出しを表すのではなく、操作をグループ化しています。しかし、驚くべきことは、ここではコンマが合法であることです。ここで、コンマの扱い方に関する興味深いブログ投稿を見つけました。

https://javascriptweblog.wordpress.com/2011/04/04/the-javascript-comma-operator/


私はそれから、return ([1, 2])両方の値を印刷するようなものですか?
cst1992

1
それは配列を返します。
私たちはテストカバレッジを

console.log((1, 2))
thedayturns

9

return関数ではありません。それはそれが発生する機能の続きです。

声明について考えて関数の名前です。それを評価しているときに、評価に集中するために、ステートメントの残りの部分を一時的に取っておかなければならないことがわかります。脇に置いた部分をのように視覚化して、空白を埋めることができます。alert (2 * foo(bar));foofoo(bar)alert (2 * _)foo(bar)それをもう一度拾います。

あなたが取っておいたのは、電話の継続でしたfoo(bar)

呼び出しはreturnその継続に値を送ります。

内の関数を評価するfooと、残りのfoo関数はその関数が値に減少するのを待ってから、foo再び受け取ります。評価する目標はまだありますが、foo(bar)一時停止しています。

return内部fooで評価する場合、どの部分もfoo値を待機しません。あなたがそれを使用returnした場所の内部の値に減少しませんfoo。代わりに、呼び出し 全体foo(bar)が値に減少し、目標が「評価foo(bar)」は完全であると見なされ、吹き飛ばされます。

プログラミングに不慣れなときは、通常、継続について人から言われることはありません。彼らがそれを高度なトピックと考えるのは、人々が最終的に継続で行う非常に高度なこといくつかあるからです。しかし、真実は、関数を呼び出すたびに、それらをずっと使用していることです。


このような考え方は、LISPやHaskellなどの関数型言語では一般的ですが、javascriptなどの手続き型言語で使用されることはありません。ほとんどの手続き型言語はそれらを特殊なケースとして扱うため、通常は継続とは見なされません。たとえばalert(2 * _)、Javascriptで後で使用するためにの続きを保存することはできません(そのようなことを行うための異なる表記法があります)。
Cort Ammon、

1
@CortAmmon私はあなたにある程度同意しますが、Javascriptには非常に強力な機能的背景(元々はCのような構文を持つSchemeサブセットの実装として意図されていました)があり、標準的な関数はないことに注意してください継続(例:call / cc)を操作するに、多くのJavaScriptライブラリで継続渡しスタイルを使用するの一般的です。そのため、初期段階で概念を理解することは、JSプログラマーにとって非常に役立ちます。
ジュール、

Javascriptがファーストクラスの継続を行わないのは事実です。return内部からのfoo値ではありません。データ構造にパックして、変数に割り当て、しばらく待ってから、後で何かにフィードすることはできません。特に、2回以上フィードすることはできません。しかし、私が言ったように、高度なトピック。
Nathan Ellis Rasmussen

同様に、継続を使用した新しい制御構造の実装:高度。しかし、my_if組み込みのように動作する関数を実装しようとすると、そのif()then{}else{}内部で組み込みを使用することを許可しても、そうすることに失敗します-特に終了する場合は、非常に高度で非常に有益ではありませんコールバックを渡すコードで上に。
Nathan Ellis Rasmussen

6

returnここでは、赤いニシンです。おそらく興味深いのは、次のバリエーションです。

function add(a, b) {
  return (
    console.log(a + b),
    console.log(arguments)
  );
}

console.log(add(2, 2));

最後の行として出力します

undefined

関数は実際には何も返しません。(2番目のconsole.logがある場合は、2番目のの戻り値を返します)。

そのまま、コードは完全に同じです

function add(a, b) {
    console.log(a + b);
    console.log(arguments);
}

console.log(add(2, 2));

1

returnステートメントを理解する興味深い方法は、void演算子を使用することです。このコードを見てください。

var console = {
    log: function(s) {
      document.getElementById("console").innerHTML += s + "<br/>"
    }
}

function funReturnUndefined(x,y) {
   return ( void(x+y) );
}

function funReturnResult(x,y) {
   return ( (x+y) );
}

console.log( funReturnUndefined(2,3) );
console.log( funReturnResult(2,3) );
<div id="console" />

returnステートメントは1つの引数を取り、[[expression]]これをスタックの呼び出し元に返すため、つまり、ステートメントがarguments.callee.caller実行されvoid(expression)、それundefinedがvoid演算子の評価になります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.