質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
ECMAScript

ECMAScriptとは、JavaScript類の標準を定めるために作られたスクリプト言語です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

1回答

4678閲覧

ES6 アロー関数の制限事項

think49

総合スコア18162

ECMAScript

ECMAScriptとは、JavaScript類の標準を定めるために作られたスクリプト言語です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

3グッド

2クリップ

投稿2016/01/07 14:51

編集2016/01/08 02:48

リファレンス

JS.next, MDN を読んでアロー関数を学びました。

実際にいろいろ書いてみて無名関数式の機能縮小版というイメージを持ちました。

制限事項

(1) アロー関数は名前付き関数式を指定できない

アロー関数は名前付き関数式のように関数名を指定する事はできません。
関数は変数名で参照する必要がある為、名前が破壊される可能性を排除できません。

JavaScript

1var fn = (i) => { return i < 10 ? fn(++i): i; }, 2 hoge = fn; 3 4console.log(fn(0)); // 10 5fn = null; 6hoge(0); // TypeError: fn is not a function

名前付き関数式では次のように書けます。

JavaScript

1var hoge = function hoge () { 2 console.log(hoge); // ここで参照する名前は "function hoge" であり、関数名は不変(改変できない) 3}; 4var foo = hoge; 5hoge = null; // 変数 hoge を破壊する 6foo(); // function hoge () { console.log(piyo); }

(2) アロー関数は this 値を束縛できない

this 値は関数定義時に既に束縛されている為、Function#call は無効です。
this 値を束縛する方法は存在しない…と思います(自信なし)。

JavaScript

1var fn = (selectorText) => { return this.document.querySelector(selectorText); }; 2 3fn('p'); 4fn.call(document.querySelector('iframe').contentWindow, 'p'); // this 値を束縛できない

質問内容

理屈は分かりますが、この2つの制限が大きく感じるので、仕様の範囲内で出来る事がないか考えてしまいます。
この2つの制限事項は私の認識で正しいのでしょうか。
間違いでしたらどんな方法で制限を回避できるでしょうか。

Lhankor_Mhy, ikuwow👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

(1) アロー関数は名前付き関数式を指定できない

関数宣言式の利点は巻き上げぐらいで、ほとんどありません。関数外部から関数にある名前を使ってその関数にアクセスしているわけではないからです。
参考: stackoverflow jp: function hoge() と hoge = function() の違いは?
また、関数宣言式にしても後からの破壊的代入を防げるわけではありません。名前の破壊を防ぎたいのであれば、constを使って定数にすべきでしょう。

上とは別に、名前付き関数の利点として、関数内部でその関数名の関数スコープである暗黙のローカル変数が作成され、それが上書きされないという利点があります。アロー関数で全く同じ方法をとることはできませんが、関数を返す関数を実行して、上書きされない関数スコープのロカール変数を使えばできます。下記のfn1を参考にしてみてください。

JavaScript

1"use strict"; 2var fn0 = (i) => { 3 return i < 10 ? fn0(++i) : i; 4}; 5var fn0x = fn0; 6console.log(fn0x(0)); // 10 7fn0 = (i) => { 8 return 0; 9}; 10console.log(fn0x(0)); // 0 になっちゃう。あかんわ。 11 12var fn1 = () => { 13 var _fn1 = (i) => { 14 return i < 10 ? _fn1(++i) : i; 15 }; 16 return _fn1; 17}(); 18var fn1x = fn1; 19console.log(fn1x(0)); // 10 20fn1 = (i) => { 21 return 0; 22}; 23console.log(fn1x(0)); // 10 のまま!やったぜ!

ただ、そもそも関数自体が上書きされること自体が想定外の動作を起こす可能性があるため、単にconstをつけて上書き禁止にした方がES6っぽいかと思います。

JavaScript

1"use strict"; 2const fn2 = (i) => { 3 return i < 10 ? fn2(++i) : i; 4}; 5var fn2x = fn2; 6console.log(fn2x(0)); // 10 7fn2 = (i) => { 8 return 0; 9}; // この時点でエラーになる!! 10console.log(fn2x(0));

(2) アロー関数は this 値を束縛できない

これは欠点というよりも一つの利点です。通常、eventなどでコールバック関数に使った場合、thisがそのeventを呼び出した要素になってしまいます。例えば、inputのイベントで書き換わった値をthis.textに入れたいとかのの動作を実装するときに、var _this = this;と書いて_this.textとして書く必要があるなど非常に不便でした。ですので、どのような呼び出され方をしても関数が定義されている環境のthisに強制的にbindするようにしたのがアロー関数です。

間違いでしたらどんな方法で制限を回避できるでしょうか。

アロー関数は通常のfunctionの単純な代替になるものではありません。

再帰関数で関数名を用いたときに、その名前の上書きを防ぎたいのであれば、関数を返す関数を実行して、スコープ内に閉じ込めるか、constで上書きそのものを防げばいいかと思います。

thisの束縛ですが、コード内にthisがなければfunctionを使った無名関数と動作は同じですが、thisがあれば必ず動作は異なります。こちらについては**回避方法はありません。**定義している環境のthisに強制的に束縛したい場合は、アロー演算子を使った方が簡単に書けると言うだけです。呼び出し方によってthisの束縛が変わるような関数を作成したい場合は、functionを使う以外方法はありません

functionを単純に短く書けるようにした物ではないため、単に短く書きたいだけであれば、最初からCoffeeScriptで書いた方がいいです。アロー関数が本来のES5ではどう解釈されるかはBabel等を用いて変換してみるとわかるかと思います。Babel: Try it outで色々試してみてください。

投稿2016/01/07 22:30

編集2016/01/08 21:19
raccy

総合スコア21735

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

think49

2016/01/08 14:44

> 関数にある名前を使ってその関数にアクセスしているわけではないからです。 名前付き関数式内では関数名をスコープとして持つと認識しています。質問本文にサンプルコードを追加しました。 > アロー関数は通常のfunctionの代わりになるものではありません。 その点は理解しているつもりです。 私が懸念しているのは「私が不可能だと思っているだけで実際には制限を回避する方法があるのではないか」という点です。 思想については仕様理解の後についてくるものだと考えている為、それ程心配してはいませんが、私自身がまだ ES6 仕様を読み始めた段階の為、不安が残っている状況です。 (1), (2) が不可能な事が仕様で保証されているのであれば、安心して不可能だという前提でコードを組めます。 結論としては、ES6 では (1), (2) の論理が保証されていると認識して問題ないでしょうか。
raccy

2016/01/08 21:15

質問を誤解していた部分もあったので、回答を書き換えました。(1)は工夫次第で同じようなことはできますが、(2)は原理的に不可能です。 仕様の理解は問題ありません。`=>`はもともとCoffeeScriptで使われていた物が逆輸入された物です。コールバック関数での`this`問題は古くからあり、呼び出し方で`this`がどうなるかわからないようなコードは嫌だ(?)という要望により導入されました。通常の関数定義をするための用途と言うより、コールバックなどの無名関数に使うことを想定しているようです。そのとき、`this`の束縛は逆に強みになるかと思います。
think49

2016/01/08 23:02

> (1)は工夫次第で同じようなことはできますが、(2)は原理的に不可能です。 コードを拝見しました。(1) はアロー関数向きではないのかもしれませんね…。 > 仕様の理解は問題ありません。 そういわれて安心しました。後程、Babelを試したいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問