0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

アロー関数を「省略記法」と呼ぶのはもうやめよう。3年目までに叩き込みたいJavaScriptの安全設計

Posted at

はじめに

JavaScriptを書き始めて、数年が経ちました。何となく使用していたアロー関数、「 function を短く書けるやつ」という認識のまま、使っていませんか?そんな方は、おそらく私と同じような状況にいます。

私は、とあるプロジェクトでVue 2を使用していました。このVue 2(Options API)などを扱う現場では、このアロー関数への理解の差が「謎のバグ」に費やす時間を左右します。

フロントエンドエンジニアとしてステップアップするなら、アロー関数への認識を 「バグを未然に防ぐための安全装置」 へとアップデートした方が良いかもしれません。

1. 「巻き上げ」という負債をコンパイルレベルで防ぐ

「巻き上げ」とは、JavaScriptのエンジンがコードを実行する前に、関数や変数の宣言を「プログラムの先頭」に移動させたかのように扱う性質のことを指します。

従来の function 命令には、宣言より前で実行できてしまう「巻き上げ(Hoisting)」という性質があります。

❌ どこで定義されたか追いにくい(大規模開発で事故の元)↓

hello(); 

function hello() {
  console.log("Hello");
}

これをアロー関数(const)に置き換えるだけで、コードの秩序が保たれます。

⭕️ 定義順にしか実行できない↓

const hello = () => {
  console.log("Hello");
};

hello();

アロー関数を使用して、「書いた順序通りにしか動かない」 という制約を自分に課す。これが、予測可能なコードを書くための第一歩です。

2. アロー関数出現前後の違い

生のJS(バニラJS)、およびアロー関数については、ES6以降かES5以前かで違いがあります。

時代 整理の単位 特徴と課題
ES5以前(アロー関数前) 手続き型(上から下に処理) / プロトタイプ すべてが functionclass による継承がなく、this は呼び出し方で決まる。var の巻き上げによる 「意図しない挙動」 と戦う自己責任の時代
ES6以降(アロー関数後) モジュール / クラス(データと処理がセット) import / export によるカプセル化(独立)と class による構造化。アロー関数の 「不自由さ(this の固定)」 を活かし、安全な設計が標準になった時代。

・ES5以前

const counter = {
  count: 0,
  start: function() {
    // 1秒ごとにカウントアップしたい
    setInterval(function() {
      // 実行時に、this をグローバルなもの(widows)として受け取ってしまう
      this.count++; 
      console.log(this.count); // NaN( = Not a Number、数値じゃない何か。実際の値は「window」。)と表示される
    }, 1000);
  }
};

counter.start();

・ES6以降

const counter = {
  count: 0,
  start: function() {
    // 1秒ごとにカウントアップ
    setInterval(() => {
      // アロー関数は自分の this を持たない
      // 外側の start メソッドが持つ this(counterオブジェクト)を固定して使う
      this.count++;
      console.log(this.count); // 1, 2, 3... と正しく増える!
    }, 1000);
  }
};

counter.start();

3. Vue 2の実務でこそ光る「thisの固定(Lexical this)」

実務でVue 2(Options API)を使っていると、this は常にコンポーネントインスタンスを指してほしいものです。

しかし、従来の関数はこの this を簡単に壊してしまいます。

❌ 失敗: setTimeout の中で this が迷子になる↓

export default {
  data() {
    return { count: 0 };
  },
  methods: {
    incrementDelayed() {
      setTimeout(function() {
        // ここでの this は window または undefined
        // this.count++ はエラーになる
        this.count++;
      }, 1000);
    }
  }
};

⭕️ 正解:アロー関数で「外側のthis」を拘束する↓

incrementDelayed() {
      setTimeout(() => {
        // アロー関数は自分の this を持たない
        // そのため、methods の this(Vueインスタンス)をそのまま使える
        this.count++;
      }, 1000);
    }

アロー関数は 「定義した場所の this を一生添い遂げる」 という一途な性質を持っています。これが、コールバック関数において最強の安全装置となります。

コンポーネントインスタンス とは「設計図(コード)」を元に、ブラウザ上に実体化された「具体的なモノ(オブジェクト)のこと。

・オブジェクト↓

// {} の形で存在しているデータ
const user = {
  name: "田中",
  age: 25
};

・インスタンス↓

// 設計図(Class)
class User {
  constructor(name) {
    this.name = name;
  }
}

// インスタンス(Instance)
// 「User」という設計図から作られた具体的な実体
const user1 = new User("田中");

4. 【重要】Vue 2における「使い分け」の鉄則

3年目のエンジニアとして整理しておきたいのが、アロー関数を 「使うべき場所」と「使ってはいけない場所」の境界線です。

箇所 推奨される書き方 理由
Vue 2 の methods function Vueが内部的に this をインスタンスにバインドするため。
methods 内のコールバック アロー関数 外側(methods)の this を引き継ぎたいため。
React / Vue 3 (Setup) アロー関数 そもそも this に依存しない関数型設計が主流のため。

「なんでもアロー関数」ではなく、「コンテキスト(this)を固定したいかどうか」 で使い分けるのがプロの視点のようです。

5. モダン環境が後押しする「厳格モード」

ReactやVue 3、あるいはViteなどのツールを使っている場合、コードは自動的に ES Modules (Strict Mode) として実行されます。

Strictモードでは、this が迷子になった時、window を書き換えるのではなく、即座にundefined を返してエラーにしてくれます。

「バグが起きても動いてしまう(静かなバグ)」よりも「エラーで即座に止まる」ほうが、開発効率は圧倒的に高くなります。 アロー関数 はこの 「安全にエラーを出す/防ぐ」 文化と非常に相性が良いのです。

<余談> JSの変遷

Options APIは、Vue 2からお馴染みの、datamethods といった「オプション(役割: dataならメモリ、methodsならアクション、など)」ごとにコードを書いていく形式のこと。Vueが内部で this をコンポーネントにバインドしてくれる仕組みが特徴。

Vueのようなコンポーネント指向のフレームワークが登場する前(主にjQuery全盛期)は、特定の「オプション(枠組み)」すらなく、当時は、「HTMLのどの要素(IDやクラス)を操作するか」 ごとにコードを書いていたそうです。

ただこれだと、コードが長くなった時にどこで何が起きているか全くわからなくなるスパゲッティコード に陥りやすく、その画期的な解決方法としてコンポーネント志向のフレームワークが出てきた、という背景があるみたいです。

しかしながら、Options API(役割ごとの整理)にも弱点があり、それが、「1つの機能に関するコードが、あちこちの引き出しにバラバラに隠れてしまう」 ことです。役割ごとに整理整頓を実現して、コードが劇的に綺麗になった一方、this の迷子問題 が出てきました。例えば、検索機能1つを作った時に、dataにもmethodsにもwatchにも関連コードがある、といった感じ。行が追いにくくなる。

そこで生まれたのが、ReactやVue 3などのComposition API。機能単位(ロジック)でまとめる関数型であり、アロー関数を主役に据えることで、this から解放され、より安全で再利用しやすい設計になった、という背景があるみたいです。

まとめ

時代 整理の単位(何ごとに書くか) 特徴と課題
jQuery時代 DOM(HTML要素) 自由だが、コードが長くなると「どこで何をしているか」不明なスパゲッティコードに陥りやすい。
Vue 2 (Options API) 技術的な役割 datamethods の引き出しに整理。綺麗になった反面、1つの機能がバラバラに散らばり、this の迷子問題も多発。
Vue 3 / React(Composition API) ロジック(機能) 検索機能なら検索機能で一箇所に固める。アロー関数を主役にすることで this から解放され、再利用性が極大化した。

時代背景で見る「関数の書き方」の変化

<jQuery時代(すべてが「自由」だったカオス期)>
・アロー関数前: どこでも function を使い、どこでも呼び出せる「巻き上げ」が当たり前。this はクリックされたボタンなどの DOM 要素にコロコロ変わり、挙動の予測が困難でした。
・課題: 自由すぎて、意図しない場所で関数が実行されたり、値が書き換わったりする事故が多発。

<Vue 2 時代(「整理」と「thisの紛失」の葛藤期)>
・アロー関数前: setTimeout などのコールバック内で this が window や undefined になり迷子に。解決策として var self = this; という不自然な書き方が横行していました。
・アロー関数後: コールバックに => を使うことで、外側の this を一生添い遂げる(固定する)ことが可能に。var self = this; を絶滅させ、実務の安全性が飛躍的に向上しました。

<現在:Vue 3 / React(「不自由さ」による安全・高効率期)>
・アロー関数の主役化: 「定義した行より下でしか使えない(巻き上げ禁止)」や「this を勝手に変えさせない」というあえての不自由さが、バグを未然に防ぐフィルターとして機能しています。
・恩恵: この制約があるからこそ、機能(ロジック)ごとにパーツを切り出しても壊れにくく、大規模な開発でも予測可能なコードを維持できるようになりました。

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?