- ベストアンサー
JSのアロー関数について
アロー関数はargumentsがない、thisがbindされている、newできないと聞いたのですが、 これは一体どういうことなのでしょうか? 初心者にもわかるように解説していただけるとありがたいです。 newできないとはオブジェクトを作成できないということなんですかね?
- みんなの回答 (7)
- 専門家の回答
質問者が選んだベストアンサー
「arguments」は「引数」という意味ではありません。 「arguments」はES5以前にしばしば使われていた、「this」と同じく関数内で効果を表す「キーワード」です。 「arguments」は、その関数に渡された全ての引数の配列のような存在です。 例えば、arguments[0]で第一引数を、arguments[1]で第二引数を得られます。 これは、幾つの引数を渡されるか分からないような関数、(例えばMath.maxのような任意の数の引数全ての中から最大の数を返す関数)において、必須のものでした。 しかし、「arguments」には配列のようで純正配列ではなかったという問題があったりして、 ES2015以降は、これに変わるレストパラメータ構文がありますので、今では非推奨に極めて近い機能であり、もう古いコードを読むということ以外では知らなくて良いことです。 そもそも、可変長関数という存在が、現在ではあまりスマートとは見られません。一部の低レベルな関数以外はそぐわないでしょう。 幾つかの値を渡したいのなら、配列として渡すように設計するのが無難です。 そして、newできないとは、new演算子が適応できない(例外を吐く)ということです。 つまりは、「hoge = new Hoge()」のHogeの部分にアロー関数は使えないということです。 そもそも、本来は使える通常の関数のほうが、『異質』なのです。 本来、オブジェクト生み出すということは、クラスベースのOOP(オブジェクト指向プログラミング)言語では、 クラス(抽象、型、ハンコの押す方)に対して、new演算子を使うことにより、 クラス内に定義されたコンストラクタと呼ばれる関数が働き、クラスの情報を受け継いだ、 インスタンスオブジェクト(実態、物、ハンコの押された印)を生成するということなのです。 しかしJSはプロトタイプベースのOOP言語です。 クラスベースと何が違うかというと、 クラスベースでは「クラス」という抽象的な構造を受け継いだ実態として、「オブジェクト」があります。 つまりオブジェクトはクラスと繋がっているわけです。 しかし、この仕組みは整頓されたコードを書くために通常貢献しますが、ちょっと変わったことをしたい場合には融通が利かないし、簡単なことをしたい時にオブジェクトを気軽に作れないのは面倒という問題がありました。 そこで生まれたのがプロトタイプベースで、オブジェクトの生成を「クラス」に縛られることなくできるようにしたのです。 例えば「{}」でオブジェクトが作り、自由に弄れるというのは、実はすごいことなのです。 そしてプロトタイプベースでは、オブジェクトは「プロトタイプ」と呼ばれる別のオブジェクトへの参照を持ち、自身のプロトタイプオブジェクトの形質を受け継ぐような格好で、オブジェクト指向を実現しています。 オブジェクトは、オブジェクトと繋がっているのです。 話を少し戻して、つまりJSでは本来「クラス」は無いし、クラスに適応するためのnew演算子も不要なのです。 そんなことをしなくとも、気軽に自由にオブジェクトを作れるのですから。 ですけれど、気軽に自由にという状態は必ずしも良いことだけではありません。 皮肉なことですが、人間はある程度制約があったほうが上手く動けるのです。 よってJSには、特定の形質を持つオブジェクトを作る方法として、クラスベースと見た目が似た仕組みが入れられる事になりました。 これが現在まで続き、ES2015以降ようやく収まりつつある混乱の元、JSの闇なのです。 今はよりまともな「Class構文」がありますし、JS本来のプロトタイプベースでのOOPもやりやすくなっているので、普通に作った関数にnewするといったことも、過去を気にしなければもう忘れていっても良いようなことです。 そしてクラスベースと見た目が似た仕組みが入れられる事にはなったものの、JSには「クラス」がありませんから、別のものがその役目を持つことになりました。 それが「関数」です。 「関数」オブジェクト自身の「prototype」プロパティ下のオブジェクト(※これと「プロトタイプオブジェクト」を混同しないでください!!理解できたらJS中級※)に、インスタンスオブジェクトの形質をプロパティとして定義することで「クラス」のような役割を持たせ、またnew演算子が適応されたときに自身が「コンストラクタ」として振る舞うようにしたのです。 ちなみに、new演算子が実際やっているのは大体、「コンストラクタ関数オブジェクト」の「prototypeプロパティであるオブジェクト」を「プロトタイプ」としたオブジェクトを作成(これがインスタンスオブジェクト)し、そのインスタンスオブジェクトをthisとしてコンストラクタ関数に通し初期化などをさせ、演算子の結果として返すということです。 ここで大事なことですが、new演算子は「コンストラクタ」に適応されます。 「コンストラクタ」としての機能を持たないものには適応できません(例外を吐きます)。 そして、通常の関数は定義されたときに、関数としての「()」演算子で呼べるという機能の他に、「new」演算子で呼び出せるという機能も付けられるのです。 しかし、より『ピュア』な関数を目指したアロー関数では後者の仕組みを持ちません。 よってnew演算子はアロー関数には使えない(例外を吐く)、アロー関数からインスタンスオブジェクトを生成することはできない、ということです。
その他の回答 (6)
- b0a0a
- ベストアンサー率49% (156/313)
分からない単語を辞書やWikipediaで調べたことがあるならわかると思いますが、 馴染みのない分野の場合、調べて分からない単語をまた調べて……と収集が付かなくなりますよね。 それと同じで、一つのことを理解するためには多くの前提知識が必要ですから、その分野に入門していきなり何かを理解することは不可能なのです。 ただそれは、勿論調べたり勉強しなくていいということではありません。 そうではなくて、一度勉強する度に、または一日勉強で、その物事の1%も理解できれば御の字という気持ちをもてばいいのです。 日本語が分かれば、説明をそれなりに見てしっかり試せば、取り敢えず分かっていないうちの1%近くは掴むことができます。 今分かりそうにないことは、「そういう事が書いてあった」程度に覚えておいて、深入りせず無視して置けば良いのです。 そういう部分で「調べて分からない単語をまた調べて……」というこだわりを頑張っても疲れるだけです。 そういった頑張りのしどころは、もう少しで分かりそうというところです。 もう少しで分かりそうという壁に達し、気分が高揚し頭が火照っているときのみ、こだわりをぶつければ、いきなり5%とか理解することもできるのです。 それは言わば勉強における奥義のようなもので、逆に言えば普段の勉強は静かに奥義のための力を貯める鍛錬なのです。
- b0a0a
- ベストアンサー率49% (156/313)
そりゃあ難しいです。 プログラミング言語学習では、何でもいきなり理解できると思わないほうが良いです。 「言語」ですから、特に最初は理屈ではなく、浅く何度も触れて慣れる・馴染むことが大事なのです。 学者のように品詞を理解していなくとも誰もが母国語を使えるように、 プログラミング言語も、それはあくまで目的を遂行するための「道具」なのですから その性質や仕組みに気を取られること無く、自然と目的だけを考えて使えることが何よりも理想なのです。 取り敢えず、アロー関数はargumentsがない、newできないとだけ覚えとけば十分なのです。 argumentsやnewについて詳しくなった時その意味が分かってきます。 逆に言うと、そうでないうちは幾ら解説されても分かることはありません。 取り敢えず最低一年はJSをみっちりやったレベルの人が気にし始めてもいいようなことです。 そして本当に仕様レベルで理解できるのは5年はかかるでしょうね。
- b0a0a
- ベストアンサー率49% (156/313)
通常の関数の場合、 function f1(a, b, c) { } と書いた場合は、暗黙的に function f1(this, a, b, c) { } と書いている(実際に書くことはできませんが)ようなものなのです そして、このf1関数がobjオブジェクトにあった場合、 obj.f1(1,2,3)と呼ぶということはドット演算子の効果で、 f1(obj,1,2,3)と呼んでいるということになります。 ここでf1の中からthisを参照すれば、ローカル変数である暗黙の引数thisが使われるのです 一方アロー関数の場合は f2 = (a, b, c) => {} と書いた場合、 f2 = (_, a, b, c) => {} のような感じで、渡される暗黙の0番目の引数をthisという名前のローカル変数に格納する仕組みを持ちません よって、f2の中からthisを参照すれば、ローカル変数はありませんから、関数外の最も近いthisを指すことになるのです。
補足
難しいです
- b0a0a
- ベストアンサー率49% (156/313)
>>コンテキストのオブジェクトがthisとなります →定義された場所でのthisとなります t0 = this o1 = { f: function() { return this } } o2 = { f: () => { return this } } console.log( o1.f() == o1 ) // true console.log( o2.f() == t0 ) // true 通常の関数定義で作られた関数におけるthisとは、『第0番目の引数』です つまり呼び出し時に、呼び出し方に応じた値になります アロー関数の場合は、この仕組が存在しません よって他の変数と同じように、関数外のthisを指します
お礼
>>> 通常の関数定義で作られた関数におけるthisとは、『第0番目の引数』です t0 = this o1 = { f: function() { return this } } o2 = { f: () => { return this } } console.log( o1.f() == o1 ) // true console.log( o2.f() == t0 ) // true こちらのどれが0番目の引数なのですか? アローだと関数外のthisを取得すると変わるということですか? 外の下から近いものになるのですか?
- b0a0a
- ベストアンサー率49% (156/313)
まあ、初心者が理解するのはかなり難しいと思います。 JSのオブジェクト指向を理解して、thisとnew周りの挙動をまず理解しなければなりません。 それから、今はもう使うべきでない過去の遺産のargumentsや、JSerのthisに対する苦悩の歴史を把握して初めて分かることです。
- b0a0a
- ベストアンサー率49% (156/313)
function文で作った関数は、関数であると同時にコンストラクタでもあります。 従って、new演算子を適応して、インスタンスを作成することができます。 しかしアロー関数はよりピュアな関数を目指したものであるため、コンストラクタの機能を持ちません。 そして、thisは他の変数と同様にレキシカルに解決されます。 よくbindされているという解説がありますが、これは誤りです。むしろその逆で開放されているのです。 また、argumentsもレストパラメータで代用可能なので機能を持ちません。
お礼
どんなに調べての下記以上に簡単なサイトが見つかりません。 https://thinkit.co.jp/article/10471 thisの値を束縛することに注意が必要です。function式ではthisは自身を参照していましたが、アロー関数式でオブジェクトのメソッドとして呼び出された場合は、コンテキストのオブジェクトがthisとなります。 コンテキストのオブジェクトがthisとなります。がさっぱりわかりません。
お礼
JS本格入門レベルの内容は、わかっていなくても、WEBアプリをガリガリ書けて、とりあえず動けば、まず良いと考えるべきなのでしょうか? 数年そのように作っているうちにわかるようになり、その時にこのレベルのことは学べばよいということでしょうか? わからないまま作っていってもダメなのかと思いましたが、 それでもいいのですね。 >>> アロー関数はargumentsがない、newできない 引数はありますが、具体的にどういう意味でしょうか? newできないとはオブジェクトの作成のnewのことですか? もう少し初心者にもわかるように解説していただけるとありがたいです。