【JavaScript】モジュール②　ES Moduleと即時関数


#はじめに

Udemyの[【JS】ガチで学びたい人のためのJavaScriptメカニズム](https://www.udemy.com/course/javascript-essence/)の講座の振り返りです。

前回の記事

https://qiita.com/nao0725/items/df8396300eb21a1fde5a




#目的

* モジュールについての理解を深める

#本題
###1. ES Moduleと即時関数

二つの動きがとても似ているのでコードで確認していく

####例1

**前提**

即時関数を定義している状態

````main.js
// moduleAという変数に対して、即時関数が定義されている
const moduleA = (function () {

  console.log('IIFE called');

  let privateVal = 1;
  let publicVal = 10;

  function publicFn() {
    console.log('publicFn called: ' + privateVal++);
  }

  function privateFn() {

  }
  // 戻り値を定義しているので、以下のオブジェクトがmoduleAに返る
  return {
    publicFn,
    publicVal
  }
})();
`````

上記のmoduleAをpublicFnを通して読んでみる


`````main.js
const moduleA = (function () {

  console.log('IIFE called');

  let privateVal = 1;
  let publicVal = 10;

  function publicFn() {
    // privateValが1ずつカウントアップする仕組みがある
    console.log('publicFn called: ' + privateVal++);
  }

  function privateFn() {

  }

  return {
    publicFn,
    publicVal
  }

})();

  // 下記のようにするとpublicFnを実行できる
  // privateFn, privateValは外部から呼べない
  moduleA.publicFn();
  // 1ずつ増えていく
  moduleA.publicFn();
  moduleA.publicFn();
  // 下記のようにすると10という値が取れてくる
  console.log(moduleA.publicVal++)
  // こちらも++すると11,12とカウントアップする
  console.log(moduleA.publicVal++)
  console.log(moduleA.publicVal++)
`````

####例2

moduleAとpublicFnをmoduleBに格納する

````main.js
const moduleA = (function () {

  console.log('IIFE called');

  let privateVal = 1;
  let publicVal = 10;

  function publicFn() {
    console.log('publicFn called: ' + privateVal++);
  }

  function privateFn() {

  }

  return {
    publicFn,
    publicVal
  }

})();

  // 以下のように即時関数を定義して格納する
  // 一般的には仮引数、実引数に値を入れて使用する
  const moduleB = (function(moduleA) {
    // 内部でmoduleAを使用
    moduleA.publicFn();
    moduleA.publicFn();
    moduleA.publicFn();
    console.log(moduleA.publicVal++)
    console.log(moduleA.publicVal++)
    console.log(moduleA.publicVal++)
  })(moduleA);
  
  // 省略して書くこともできる
  // moduleAはオブジェクトなので、直接publicFn, Valを分割代入可能
  const moduleB2 = (function( {publicFn, publicVal }) {
    // moduleAを使用していないのでmoduleAを削除
    publicFn();
    publicFn();
    publicFn();
    console.log(publicVal++)
    console.log(publicVal++)
    console.log(publicVal++)
  })(moduleA);

  // さらに名前をつけて書くことも可能

  const moduleB3 = (function( {publicFn: Fn, publicVal: Val }) {
    // このようにすると上記のmoduleB2と同じ結果が出力される
    Fn();
    Fn();
    Fn();
    console.log(Val++)
    console.log(Val++)
    console.log(Val++)
  })(moduleA);
`````

####例3

即時関数で書いていたものをES moduleに書き直す

````moduleA.js
// moduleAの値をそのままコピー
  console.log('ES Module called');

  let privateVal = 1;
  // publicとあるものは外部に露出したいので（ファイルの外で使いたい）exportをつける
  // 渡す時にエラーが発生しないようにプリミティブ型でなくオブジェクトとして定義する
  export let publicVal = { prop : 10 };

  export function publicFn() {
    console.log('publicFn called: ' + privateVal++);
  }

  function privateFn() {

  }
`````

````moduleB.js
// // moduleBも全体をコピーして持ってくる
// const moduleB = (function(moduleA) {
  // 以下の書き方に変更
  import { publicFn as Fn, publicVal as Val} from "./moduleA.js";
  Fn();
  Fn();
  Fn();
  // moduleAに合わせて変更
  console.log(Val.prop++)
  console.log(Val.prop++)
  console.log(Val.prop++)
``````

今日はここまで！

#参考にさせて頂いた記事

* [【JS】ガチで学びたい人のためのJavaScriptメカニズム](https://www.udemy.com/course/javascript-essence/)
* [Let'sプログラミング JavaScript入門](https://www.javadrive.jp/javascript/)