JavaScriptの変な書き方が嫌い

JavaScriptって、最初はオブジェクト指向の概念がなかったんですよ。
ES2015っていうバージョンでできるようになったのすが、2015年ってめちゃくちゃ最近じゃないですか。
あとからあとから機能が追加されて、しかも他の言語とちょっと違う書き方が多くてすごく気持ちが悪い言語。
しかも昔はブラウザによって動いたり動かなかったりということが多くて、正直言って大嫌いな言語でした。

少し前まで、要件でIEで動くように見たいなものもあったので、あんまり新しい仕様の記述はさけたりしていましたが。
ですので、フロントエンドで何かしたいときは、基本的にjQueryを使っていたんですが、そろそろオワコンっていう声も聞こえてくるし、VueとかReactとかSPA(Single Page Application)ってのもそろそろメジャーになってきたので、さすがにもうIEも絶滅しただろうし、まじめに最新のJavascript技術をやっていこうかなという今日この頃です。

まずは、JavaScriptの気色悪い関数宣言方法についてまとめていこうかと思います。

関数宣言(function文)

こんな感じです。

//function(関数)の定義
function test(){
  console.log("hoge");
}
//呼び出し方法
test();

どの言語でも共通する一般的な関数宣言の方法だと思います。
私は基本この方法で書いています。
因みに、関数定義の前に関数呼び出しが来ても大丈夫です。C言語なんかはダメなので、先に定義するか定義ファイルを読み込むかする必要がありますが、JavaScriptの場合は関数宣言だけ先に読み込んで登録してくれるようです。
問題は次です。

関数式

//function(関数)の定義
let hoge = function (){
  console.log("hoge");
}
//呼び出し方法
hoge();

関数を変数に代入している感じですかね?オブジェクト指向とはちょっと違う書き方で気味が悪いです。
JavaScript以外でこういう表記法があるのかわかりませんが、少なくとも主要な言語でこういったことができるのはJavaScriptだけだと思います。
強いて近い感じの機能をあげるとすれば、C言語の関数ポインタでしょうか?
因みに、関数名がない関数定義を無名関数(もしくは匿名関数)と呼びます。
無名関数はほかの言語にもあったりします。(PHPにもありますね)
また、関数名はついていても構いません。構いませんがどうやって使うんだろうか?

関数名を考えなくても関数を定義できるというのが利点といわれています。まぁ、この場合は代わりに変数名が必要なので、結局同じなのではというような気がしますが…。
とはいえ、SPAのフレームワークだと大体この書き方をしているので、この書き方にも慣れておかないといけないでしょう。
まぁ、本当は別の理由があるのです(後述)

無名関数

無名関数は他の言語でもあるのですが、なぜかJavaScriptはこの書き方を多用する傾向があります。
たとえば。

fuga = hoge(function(){
  console.log("hoge");
});
fuga();

関数の引数に、別の関数の戻り値を入れたいっていう場面は結構あるんですが、これを無名関数でやることが多いんですよね。
数行の小さい関数ならまぁいいんですが、1画面以上のデカい関数とか、関数内で別の関数に対してこの処理が入ると、さらに長くなっちゃう傾向があります。
そうなると、書いてるときはいいのかもしれませんが、いざコード解析しようというときに非常に見通しがわるいんですよ。
一般的に関数を長くしてはいけません、別の関数に分けましょう、と言われているのですが、JavaScriptはなぜかガン無視してますよね?

だから嫌いなんだよ

アロー関数

無名関数の記述方法でこういうのが追加されました。

//今までのやり方
function(a, b) {
return a + b
}
//アロー関数
(a, b) => {
return a + b
}

functionって書いてたのを=>にできますよっていうただそれだけの話です。
ちなみにPHPでも7.4でこの記法が追加されました。
=>はアロー演算子・・・でいいのかな?
ふつう、アロー演算子ってC言語の構造体とかオブジェクト指向でインスタンスが持ってるプロパティーを指定するのに使ったりしてますね。

即時関数

無名関数関連で即時関数も語らないとだめですね。
こういうやつです。

(function () {
    //処理
}());

jQueryとかで何かするときにとりあえずこれの中に処理を書きますね。
普通の無名関数との違いは、即時関数はその名の通りすぐ実行されます。
なんでこんなのを使うかというと、変数のスコープ汚染を防ぐためです。
スコープというのは、定義した変数がどこからどこまで使えるかということです。
一般的な言語は、アプリケーション全体、定義したファイル内、関数内、ブロック内 の4パターンがデフォルトの範囲で、言語によっては名前空間という定義ができて、自由にスコープを設定できます。

で、JavaScriptなんですが、基本的にブロックスコープの概念がありません。つまり、プロジェクト(HTML内とかリンクしたJSファイル内で)全体で、別の用途で使っている変数の名前がかぶっちゃうと、バグの原因になります。
よって、即時関数で書くと、関数になってスコープが付くので安全になるというのが本当の理由です。

ですが、ES2015以降は”let”で宣言して使えばブロックでのスコープが付くようになりました。
ですので、本当はこんなことしなくてもいいはずなのですが、JavaScriptのネイティブスピーカーたちは即時関数に慣れすぎてしまって、結局使っているんですよね。

型なし言語

変数宣言の話も出てきたので、型についても触れないといけません。
型というのは、変数にどんなものを入れるかの定義のことで、数値なら数値型、文字列なら文字列型で宣言しします。比較的古い言語は静的型付け言語といって、宣言した型に合うデータしか代入できません。
一方、JavaScriptは変数宣言時にデータ型を指定する必要がありません。スクリプト実行時に、必要に応じてデータ型が自動的に変換されます。こういった言語を動的型付け言語といいます。
動的型付け言語は、一見便利なように見えますが、バグの温床になります。数字と文字列で計算とかもできちゃうわけですからね。ちなみに、Pythonも動的型付け言語です。
PHPは一応、静的型付け言語ですが、厳格ではなく、たとえば一致しない型が引数と渡されたても、一致させることができる場合暗黙の型変換がなされます。これも一見便利ですが怖いですよね。

一応、JavaScriptでもTypeScriptを用いて型付にする方法があります。
TypeScriptはJavaScriptのスーパーセットですので、JavaScriptと同じ方法で記述できます。ただ、作ったのがマイクロソフトなんですよね。あの会社が作ったものっていきなり梯子を外してなかったことにすることがあるので、あんまり勉強したくないんです。将来的にTypeScriptが持つ機能がJavaScript本体にも導入される可能性も無きにしも非ずなので・・。まぁオープンソースなのでなくなるってことはないとは思いますが、選択肢の一つとしてもいいかもしれません。

クロージャ

※2020/12/9 追記
JavaScriptこれも他の言語ではあまり使わない概念としてクロージャを忘れていました。
Wikipediaから引用

クロージャ(クロージャー、英語: closure)、関数閉包はプログラミング言語における関数オブジェクトの一種。いくつかの言語ではラムダ式や無名関数にて利用可能な機能・概念である。引数以外の変数を実行時の環境ではなく、自身が定義された環境(静的スコープ)において解決することを特徴とする。

全く何を言っているか意味不明ですが、要は関数の中に関数があるようなやつです。
こんな感じ

function outer(){
    var x = 1;
    return function inner (){
      console.error(x)
      x = x+1;
    };
}

var f =  outer();
f();  //1  を出力
f();  //2 を出力
f();  //3 を出力
f();  //4 を出力

ポイントは、関数オブジェクトの中でローカルな変数を保持できるという点でしょう。
これを、クロージャなしで実装するとなるとグローバル変数でxを定義するか、コール元で引数と戻り値で状態を管理する必要があります。

クロージャ自体はC++/C#/Java/PHPなど結構メジャーな言語でも使えます。が、あんまり使っているところを見ないですよね?
というか、なんとなく、オブジェクト指向っぽいコードのように思いませんか?おそらく、他の言語では、クロージャを使わなくてもオブジェクトでよくね?ということなんだと思います。
オブジェクト指向が使えなかったための苦肉の策で使われているのだと思います。

実際、JavaScriptではクロージャとは知らずに使っていると思います。よくありがちなのが、jQueryでボタンの二重押しを防止するこんなコード

$(function(){
    var isClicked = false;
    $('#form').submit(function(){
        if (isClicked) {
            alert('クリック済みです');
            return false;
        }
        isClicked = true;
    });
});

プログラミング初学者の方へ

お勧めの本の記事を書きました。こちらもどうぞ

JavaScriptの入門者向けお勧め本
これからWebアプリケーションの作成をしたいという方向けにJavaScript関連のお勧めの入門書をまとめてみました。プログラミング初学者の方へWebアプリケーションエンジニアを目指そうとしている方は、フロントエンドとバックエンドどっちがい...
タイトルとURLをコピーしました