ES6はすぐにアロー関数を呼び出しました


149

なぜこれはNode.jsコンソール(4.1.1と5.3.0でテスト済み)では機能するが、ブラウザー(Chromeでテスト済み)では機能しないのですか?このコードブロックは、ログを記録する無名関数を作成して呼び出す必要がありますOk

() => {
  console.log('Ok');
}()

また、上記しながら、作品のノードで、これは動作しません。

n => {
  console.log('Ok');
}()

これも:

(n) => {
  console.log('Ok');
}()

奇妙なことに、パラメータが追加されると、実際SyntaxErrorにはすぐに呼び出される部分にaがスローされます。


8
良い質問。パラメータ化された両方のバージョンは、Babelで動作します
CodingIntrigue

2
興味がなくても(n => { console.log("Ok"); })();機能しますか?
CodingIntrigue

はい(n => { console.log("Ok"); })()クロームDEVコンソールでさえも動作します
XCS

したがって、3年後の答えは?確かに以下の3つの答えのうちの1つは受け入れられるべきですか?
joedotnot

@joedotnot明確な答えが得られませんでした。ほとんどがNode.jsの奇妙な実装でした。Node.js最初のバージョンの最新バージョンでは動作していないようです。
XCS

回答:


194

名前を必要とせず、有効なJavaScriptにする関数定義ではなく、関数式にする必要があります。

(() => {
  console.log('Ok');
})()

IIFEに相当

(function(){
   console.log('Ok')
})();

そして、これがNode.jsでは機能するがChromeでは機能しない理由として考えられるのは、パーサーがこれを自己実行機能として解釈するためです。

function() { console.log('hello'); }();

で正常に動作しますNode.js。これは、関数式とクロームとFirefoxとブラウザの解釈の最もそれこの方法です。手動で呼び出す必要があります。

JavaScriptでは、括弧にステートメントを含めることができないため、関数式を期待するようにパーサーに指示する最も広く受け入れられている方法は、括弧で囲むことです。この時点で、パーサーはfunctionキーワードを検出すると、それを関数宣言ではなく関数式として解析することを認識します。

パラメータ化されたバージョンについては、これは動作します。

((n) => {
  console.log('Ok');
})()

4
最初の例は機能しNode.js、実際に値を記録します。私の質問は、なぜそれが機能するのですか?そして、なぜパラメーターを追加したときにそうならないのですか?
XCS 2016年

1
私はIIFEs にかなり精通しており、自分のコードを修正する方法を知っています。たとえば、パラメーターなしで機能していてもIIFEnパラメーターが追加されたときに機能しないのはなぜですか。
XCS 2016年

3
私は反対票を投じませんでしたが、問題は、パラメーターなしのまったく同じ定義が機能するのに、パラメーター化されたバージョンがNodeで機能しない理由です-それは、匿名関数のNode / Chrome実装の違いを尋ねていません
CodingIntrigue

1
知っておくと
便利です

しかしfunction(){}()、矢印関数に相当するものは何ですか?関数オブジェクトが必要な場合、公開された関数式はそれを防ぎます。
dabadaba

18

これらはいずれも括弧なしでは機能しません。

どうして?

仕様によると:

  1. ArrowFunctionAssignmentExpressionの下にリストされています
  2. CallExpressionLHSは、MemberExpressionSuperCallまたはCallExpressionである必要があります

だから、ArrowFunctionはのLHSにすることはできませんCallExpression


これ=>が解釈される方法で効果的に意味することは、代入演算子などと同じ種類のレベルで機能すること=です+=

意味

  • x => {foo}() しないとなって(x => {foo})()
  • 通訳者はそれを次のように解釈しようとします x => ({foo}())
  • したがって、それはまだSyntaxErrorです
  • したがって、インタプリタ(はが間違っていたと判断し、SyntaxErrorをスローします

ここでもバベルのバグがありました。


これらはいくつかの有効なポイントですが、最初の有効なバージョンを次のように置き換えようとすると、機能() => ({console.log('Ok')}())しなくなります。そのため、実際にはそのようには解釈されません。
XCS 2016年

@Cristyこれは有効なArrow Functionプロダクションではありません。オブジェクトリテラル(かっこで囲まれている)を使用してオブジェクトを作成しようとしていると考えconsole.log(...)られ、有効なキー名ではありません。
thefourtheye 2016年

@Cristy:はい、上記の解釈の部分(「意味」ビット)は正確ではないかもしれませんが、仕様の部分は私の知る限りです。:それはまた、私はV8から取得することエラーフィットSyntaxError: Unexpected token ((指さし(()終わりではなく、(中にconsole.log(...))。
TJクラウダー2016年

@TJCrowder正解です。エラーメッセージが変わり、私が言おうとしていることが伝わらないので、それを打ち消します(つまり、(有効な解釈を見つけようとする試みを使い尽くした後、インタプリタが諦めました。 「この場合、これは間違っているはずです」)。インタプリタが実際にどのように書かれているかがわからないため、とにかく間違っている可能性があります
Paul S.

この位置では有効なトークンではないのでしょうか、セミコロンを挿入しようとしないのですか?
thefourtheye

2

このような問題が発生する理由は、コンソール自体が現在対象としているコンテキストのグローバルスコープをエミュレートしようとするためです。また、コンソールに書き込んだステートメントや式からの戻り値をキャプチャして、結果が表示されるようにします。例えば:

> 3 + 2
< 5

ここでは、式のように実行されますが、ステートメントのように記述しました。通常のスクリプトでは値は破棄されますが、ここではコードを内部でマングルする必要があります(ステートメント全体を関数コンテキストとステートメントでラップするなどreturn)。これにより、発生している問題を含め、あらゆる種類の奇妙な影響が発生します。

これは、スクリプト内の一部の裸のES6コードが正常に機能するがChrome Dev Toolsコンソールでは機能しない理由の1つでもあります。

NodeとChromeコンソールでこれを実行してみてください:

{ let a = 3 }

ノードまたは<script>タグでは問題なく機能しますが、コンソールではが得られUncaught SyntaxError: Unexpected identifierます。また、ソースへのリンクが表示されます。このリンクをVMxxx:1クリックすると、評価されたソースを検査できます。次のように表示されます。

({ let a = 3 })

それで、なぜこれをしたのですか?

その答えは、コードを式に変換して、結果を呼び出し元に返し、コンソールに表示できるようにする必要があるということです。これを行うには、ステートメントを括弧で囲み、式を作成しますが、上記のブロックを構文的に不正確にします(式にブロック宣言を含めることはできません)。

コンソールはコードを賢くすることでこれらのエッジケースを修正しようとしますが、それはこの回答の範囲を超えていると思います。バグを報告して、修正を検討する必要があるかどうかを確認できます。

これは非常によく似た良い例です:

https://stackoverflow.com/a/28431346/46588

コードを機能させる最も安全な方法は、コードを式として実行できることを確認し、SyntaxErrorソースリンクを調べて実際の実行コードを確認し、そこからソリューションをリバースエンジニアリングすることです。通常は、戦略的に配置された一対の括弧を意味します。

要するに:コンソールは正確にできるだけグローバル実行コンテキストをエミュレートしようとしますが、相互作用の制限のためにV8エンジンを持つとJavaScriptセマンティクスこれは時々解決するのは難しいまたは不可能です。


1
それが全体のポイントです、私はパラメーターを気にしますが、それはパラメーターセットでは機能しません。
XCS 2016

わかりました。違いは、Chrome Dev Toolsコンソールが実際にコードを実行する方法にあります。これを反映するように答えを編集します。
KlemenSlavič16年

0

私はこのような質問をしました:

@getify私はこの質問をしました:#IIFEパターンを生成するには、関数宣言の周りのパランを使用してそれを関数式に変換してから呼び出します。アロー関数IIFEで、なぜ私たちはパランが必要なのですか?アロー関数は、デフォルトではすでに式ではありませんか?!

これがカイルシンプソンの答えです。

矢印関数 exprですが、 "演算子の優先順位"(sorta)のかっこb / cが必要です。そのため、arrow-IIFEを呼び出す最後のかっこは、その本体の最後のトークンだけではなく、関数全体に適用されます。 。

x => console.log(x)(4)

(x => console.log(x))(4)

— getify(@getify)2020年6月12日


私の質問は、なぜそれがいくつかのコンパイラでは機能し、他では機能しないのかということでした。
XCS

これは、コンパイラが異なると、コンパイラも異なるブラウザと同じように、コンパイラによって動作が細部で異なるためです
Ershad Qaderi

あなたの言う通り、動作は異なりますが、JavaScriptの仕様はすべて同じです。私はどちらが正しいのか、JS仕様がこのケースについて何を言っているのか、そして特にそれが議論なしで機能するが議論なしで機能することがどのようになり得るかについて知りました。もっと技術的な対応を探していました。
XCS

あなたの例はかなり明白です、最初のケースでは実際にを呼び出す必要がありますconsole.log(x)(4)
XCS

私はここで推測しているだけですが、次のように説明するのは非常に合理的だと思います。矢印関数の式では、パラメーターを使用しない場合は括弧を使用する必要があり、これにより、エンジンがこれが矢印であることを非常に明確にします関数式ですが、単一のパラメーターがある場合、括弧は任意です。これは関数であり、エンジンを混乱させることはあまり明確ではない可能性があります。混乱を解決するには、関数式全体を括弧で囲む必要があります
Ershadカデリ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.