ESM 模組 (ES6 Modules or JavaScript Modules)


Posted by Calon on 2022-04-26

  • ESM 預設嚴格模式:無論有沒有使用 'use strict',都會自動變成 'use strict'。
  • 作用域獨立:每個模組都是獨立作用域,也就是 <script type="module"></script> 都擁有一個自己的空間,不可以跨域去取值。
<!-- 沒有模組化的 <script>,可以從另一個 <script> 順利取到已宣告的變數的值 -->
<script>
    let sayHi = 'hi';
</script>
<script>
    console.log(sayHi); // hi
</script>


<!-- 寫成 <script type="module"> 時,
就無法從另一個 <script> 取到  <script type="module">  已宣告的變數的值 -->
<script type="module">
    let sayHi = 'hi';
</script>
<script>
    console.log(sayHi); // Uncaught ReferenceError: sayHi is not defined
</script>

運作

在使用 ESM 的 <script> 加上 type="module"

<script type="module"></script>

Export 匯出

export 可以匯出物件、函式和純值。分為兩種,根據匯出的形式不同,會影響 import 時的寫法:

預設匯出(default export):

  • 在匯出時沒有給予特定名稱。
  • 一個檔案裡面只能有一個 default export
  • 在實作開發時常用到。
// 直接匯出純值
export default 1;

// 代入變數
const a = 1;
export default a;
// 匯出物件
const obj1 = {person: 'Tom'};
export default obj1;
// 匯出多個物件
const obj1 = {person: 'Tom'};
const obj2 = {person: 'Mary'};
export default {obj1, obj2}; // 使用物件縮寫(Object shorthand)形式匯出


預設匯出(default export)可以直接匯出匿名函式。

export default function(){
    console.log('Hi, I\'m function');
};


具名匯出(named export):

  • 在匯出時會給予特定名稱,並在匯入時代入該名稱匯入。
  • 一個檔案裡面可以有多個 named export。
  • 常使用在函式庫。
  1. export 後緊接使用 let, const 宣告後再匯出。

    export let a = 1;
    export const obj1 = {person: 'Tom'};
    
  2. 使用函式陳述式匯出

    export function sayHi(){
     console.log('hi');
    };
    
  3. 使用物件縮寫(Object shorthand)形式匯出
    ```javascript=
    let a = 1;
    const obj1 = {person: 'Tom'};
    const obj2 = {person: 'Mary'};

export {a, obj1, obj2};


匯出前可以使用 `as` 修改名稱。
```javascript=
const obj = {dog: 'kuro'};

export {obj as newObj};


Import 匯入

匯入 預設匯出(default export)

預設匯出因為在匯出時沒有賦予名稱,所以匯入時要賦予一個名稱。

// export file
export default function(){
    console.log('Hi, I\'m function');
};

// import file
// import 要賦予的名稱 form '檔案位置(html 要加上 .js)';
import fn form './js/esm.js';


匯入 具名匯出(named export)

  • 需要使用物件解構的方式將特定模組取出,並且模組名稱需要一致。
// export file
function fn(){
    console.log('Hi, I\'m function');
};
const obj = {dog: 'kuro'};

export {fn, obj};


// import file
import {fn, obj} form './js/esm.js';
fn(); // 'Hi, I'm function'
console.log(obj); // {dog: 'kuro'}
  • 在匯入時也可以和匯出時一樣將模組重新命名。
// export file
export function fn(){
    console.log('Hi, I\'m function');
};


// import file
import {fn as newFn} form './js/esm.js';
newFn(); // 'Hi, I'm function'
  • 也可以使用 * 全部匯入。此時需要使用 as 指向一個新物件變數,此物件內容就是匯出的所有模組。
// export file
function fn(){
    console.log('Hi, I\'m function');
};
const obj = {dog: 'kuro'};

export {fn, obj};


// import file
import * as allObj form './js/esm.js';
allObj.fn();
console.log(allObj.obj);


同時匯入 預設匯出(default export)、具名匯出(named export)

// export file
export default function (){
    console.log('Hi, I\'m function');
};
export const obj = {dog: 'kuro'};


// import file
// 為預設匯出賦予名稱 fn,將所有具名匯出指向到新的物件 allObj
import fn, * as allObj form './js/esm.js';
fn();
console.log(allObj.obj);


Side Effect 模組

有些模組沒有使用 export,例如可以直接執行的 IIFE,不需要另外呼叫就可以直接執行可稱為 Side Effect 模組。
常見案例有早期版本的框架,直接將方法綁定在 window,不需要呼叫即可運作,例如:jQuery, angularJs

// 不需要進行匯出,可以直接用 import 匯入運作
(function(){
    console.log('hi');
})();

//import file
import '檔案位置.js'; // hi
// jQuery.js 範例
(function(global){
  global.$ = {
    sayHello() {
      console.log('Hello, world');
    },
    myName: 'world',
    obj: {
      myName: 'world',
    },
    arr: [1, 2, 3],
  }
})(window);

/* app.js */
console.log($.myName); // 'world'
$.sayHello(); // Hello, World
console.log($.obj.myName); // world'
console.log($.arr[0]); // 1

參考資料

#javascript #ES Module







Related Posts

Git 常忘指令

Git 常忘指令

[進階 js 06] 體驗 JS 引擎的一天,理解 Execution Context 與 Variable Object

[進階 js 06] 體驗 JS 引擎的一天,理解 Execution Context 與 Variable Object

[筆記] JavaScript: Understanding the Weird Parts - Build your own lib/framework

[筆記] JavaScript: Understanding the Weird Parts - Build your own lib/framework


Comments