🏹

クラサバアプリ脳で Webアプリを学ぶ(vue.js + python) 40代後半 のメモ その3 JavaScript関数

2022/05/21に公開約3,800字

アロー関数。こいつは手強いぞ。(省略の文化)

普段はVB.net(ようやくC#がすこし馴染んできた)を利用していましたので、JavaScriptに対する知識は古いまま(2010年頃の知識しかない)。巷にあふれるサンプルコードや、参考書籍内に出てくる関数表記法「アロー関数」。とにかくこいつがぱっと見何をしているのかが理解できないおっさんがここにいます(頭硬くなったなあと思う今日この頃・・)。

関数について自分なりにまとめていきます。
アプリ学習時に読んでいた書籍ではないですが、Software Design2022年01月号の特集

https://gihyo.jp/magazine/SD/archive/2022/202202
に、JavaScriptの関数作成方法が紹介されています。雑誌掲載内容の記述を参考にしていきますが、

戻り値を代入する関数呼び出し

const hoge = getHoge();
console.log(hoge); // "HogeMoji"

この形だと、ああ、getHoge は 後ろに()が付いてるから、関数を呼び出して戻り値を変数に代入しているんだね、って読み解けます。
呼び出される関数は

function getHoge(){
    return "HogeMoji";
}

で定義する。戻り値のある関数、と見て分かります。
ところが、アロー関数の表現方法

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions#Description
宣言を見ると
const ichiFueru = (n) => {
    return n + 1;
}

この表記方法は、「ECMAScript2015より導入された」とSoftware Design2022年01月号に記載があります。が、初めて見ると、なんじゃこれ?なイメージです。
上記の記述の場合、return が現れるため、「ああ、 n + 1 を戻すのだろう」という想像もつくのですが、Software Designの追加の解説では
「引数が1つの場合、引数のカッコが省略できる」とありますので、

const ichiFueru = n => {
    return n + 1;
}

となって、functionで宣言していた時の呼び出しに紐づいていた
「() があるので、関数なんだろうな」 という想像からは外れていきます。
さらに、簡潔文体なるものがあり、処理内容が1行であれば

const ichiFueru = n => n + 1;

と表記できるとのこと。自分としては、もはや関数には見えなかった・・。
(ちなみに、カッコ類を省略していないのは「ブロック文体」と呼ぶそうです・・)
アロー関数の読み解きに慣れないと、何をしているのかがすごく分かりづらいというのが当初抱いた印象です。

.Netだって、ラムダ式でアロー演算子、でてくるじゃん

ちなみに、.Net(VB.net または C#)の世界にもラムダ式があり、C#にはアロー演算子が出てきますが、VB.netのラムダ式には、

https://atmarkit.itmedia.co.jp/fdotnet/rapidmaster/rapidmaster_02/rapidmaster_02.html
上記リンクの説明にもあるように、

Function(左辺)Sub(左辺)

なので、アロー演算子は現れません(正直なところ、当初ラムダ式もかなり異質なものに思えました)。VB野郎には馴染みのない表記方法となり、これが理解を妨げる一因となっていました。

アロー関数は、今までの問題点を解決するもの??

アロー関数記述は、従来の問題点解決のための記法であると、Software Design特集でも記されています。
まず、構文が長いのは良くないとのこと(自分は、functionとか記述があるほうが断然わかりやすいのだが、これも時代の流れなのか・・)。
次に、mdnドキュメントにもありましたが、アロー関数は new 演算子を使ってコンストラクタとして振る舞えないとのことで、純粋な「関数」として扱うことを明示できるということですね。

JavaScriptでの オブジェクトって何を指すのだろう?

コンストラクタという言葉が出てたので、オブジェクトというキーワードが気になりました。mdnドキュメントを参照すると

https://developer.mozilla.org/ja/docs/Learn/JavaScript/Objects/Basics
抜粋すると

オブジェクトとは関連のあるデータと機能の集合です。(機能はたいていは変数と関数で構成されており、オブジェクトの中ではそれぞれプロパティとメソッドと呼ばれます。)

とあります。
ここでの、各キーワードを自分なりの解釈を当てはめていきます。

・オブジェクト ・・・ 関連のあるデータと機能の集合(そのまんま)
・変数   ・・・ プログラム内の数値、文字列を取っておく「箱」
・関数   ・・・ 与えられた入力値に何らかの処理を行い、その結果を戻す「しくみ」
・プロパティ ・・・ 属性(クラス内の特定スコープ範囲の変数(プロパティは状況よっては振る舞いを持たせられちゃうが、ここでは単一宣言変数と捉える))
・メソッド   ・・・ 振る舞い(クラス内関数)

つまりは、「オブジェクト」の「データ」の扱い(初期化)がキモと考えます。
そこで、出てくる別のキーワード
「オブジェクトリテラル表記法」

let o = {a: 'foo', b: 42, c: {}}

で、オブジェクト の データ の 中身 を リテラル表記 で キーと値を波カッコで括りデータの初期値として定義している例から、オブジェクトが想像できます。

正直、まだ掴みきれていませんが、何となく、オブジェクト指向言語の

・new インスタンスを作成
・コストラクタの引数や、コンストラクタそのものでデータの初期定義を実行
・インスタンスに対して、メソッド、プロパティを利用し処理を進める

という流れとは異なる形であることも認識できます。

オブジェクト指向とそうでない指向(あえてこう書きます)での this

ここで、mdnのドキュメント

https://developer.mozilla.org/ja/docs/Learn/JavaScript/Objects/Basics#what_is_this
に、thisの扱いが表記してあります。固有名詞を指定せず、thisというキーワードを利用する例です。
Software Design特集で、
・thisは利用スコープ範囲で役割が変わる
とありました。グローバルスコープでは thisは グローバルオブジェクトの Window なんだそうです(全く知らなかった)。確かに、C#などのクラス内参照では、thisは自分自身を差す、と解釈しています。JavaScript全体で考えたら、this は Window で 問題なさそうです。
何も考えずに利用していると、this は 使われる場所に従って、意味がころころ変わりそうで非常に危険な香りがします・・。
アロー関数の場合は、関数の定義場所で this が静的に決まるので、アロー関数をメソッド内で作成すれば、そのアロー関数のthisはメソッドに属したオブジェクトを指すので、thisという表記に柔軟性(決めうち)を持たせられ、記述に汎用性が生まれます。

こうして、オブジェクトを扱うのに、オブジェクト指向とそうでない指向での使い分けの一部が、何となく意識できるようになりました(関数として1行に思いを込めるというのが重要な要素な気がします)。この場合、どちらが良い、悪いという考え方ではなく、目的によって使い分けることで利便性を高めるべきと考えるのが自然なのだと捉えました。

だから、PythonやJavaScriptのような言語を使うときに、JavaやC#とは違った印象を持つ言語であるという感じがするのだというのが、何となくわかったような気になりました(何となく・・)。
そして、オブジェクト指向言語の側面も併せて保有するというスタイルで、言語仕様が決められているのであると・・。

ここでのまとめ

一部の取得済みの言語の認識をそのまま当てはめるのではなく、JavaScriptがどのような生い立ちで今のような形になり、省略、簡略表記を受け入れることで、過去の問題点を改善しようとしていることを意識する必要がありますね。そして、その記述方法を、「開発言語毎に異なる動作を正確に把握する(C#とは違う言語であることを把握し、違いを明確にする)」」

うーむ、非常に奥が深い。まだまだ探究は続きそうです。

GitHubで編集を提案

Discussion

ログインするとコメントできます