1. 程式人生 > 其它 >模組化開發 -ES Module&&CMD&&AMD

模組化開發 -ES Module&&CMD&&AMD

技術標籤:模組化javascriptmodule

概述

  • 主流的前端開發正規化之一
  • 主流的程式碼組織方式,劃分模組,單獨維護,降低成本

模組化規範

模組化標準 + 模組化載入器

CommonJS規範 node提出的一種約定

  • 一個檔案是一個模組
  • 每個模組都有單獨的作用域
  • 通過module.exports匯出成員
  • 通過require函式載入模組

CommonJS是以同步模式載入模組,瀏覽器端支援不好

AMD(Asynchronous Module Definition) 非同步的模組定義規範
Require.js 實現了AMD規範,是一種模組載入器

// 定義一個模組
define('module1',
['jquery','./module2'],function($,module2){ return { start:function(){ $("body").animate({margin: '200px'}) module2() } } }) // 載入一個模組 require(['./module1'],function(module1){ module1.start() })

大多數第三方庫都支援AMD規範

  • AMD使用相對複雜
  • 模組JS檔案請求頻繁

Sea.js + CMD 淘寶推出的,後來被AMD相容

// CMD 規範 (類似CommonJS規範)
 define(function(require,exports,module){
     // 通過 require 引入依賴
     var $ = require('jquery')
     // 通過exports 或者module.exports對外暴露成員
     module.exports = function(){
         console.log('module 2 ~')
         $('body').append('<p>module2</p>')
     }
 })

模組化標準實現規範


NodeJS 中一般 CommonJS
瀏覽器一般 ES Modules規範

commonJS是NodeJS中內建模組,直接使用匯出就可以
ES Module 是ES2015 新增,開始相容問題很多,是在語言層面實現模組化,隨著webpack等打包工具,成為最廣泛的模組標準

ES Module

基本特性
ES中採用嚴格模式,忽略 ‘use strict’
每個ES Module 都是執行在單獨的私有作用域
ESM 是通過Cors 的方式請求JS模組的
ESM 的script 標籤會延遲執行指令碼 相當於添加了difine屬性

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ESModule.html</title>
</head>
<body>
    <!-- 通過script 新增type = module 的屬性,可以實現ES Module的標準執行其中JS程式碼 -->

    <script type="module">
        console.log('module1')
    </script>
    <!-- 1. ES中採用嚴格模式,忽略 'use strict' -->
    <script type="module">
        console.log(this)
    </script>
    <!-- 2. 每個ES Module 都是執行在單獨的作用域 -->
    <script type="module">
        console.log(this)
        var foo = 100;
    </script>

    <script type="module">
        console.log(foo) //訪問不到,沒有全域性變數汙染
    </script>
    <!-- 3. ESM 是通過Cors 的方式請求JS模組的 -->
    <script type="module" src="https://libs.baidu.com/hquery/2.0.0/jquery.min.js"></script>

    <!-- 4. ESM 的script 標籤會延遲執行指令碼  相當於添加了difine屬性 -->
    <script>
        // script 不新增module 會阻塞程式碼執行
        // 新增之後會先載入程式碼再執行JS模組
    </script>
</body>
</html>

ES Module匯出
利用export關鍵詞

export var name = 'foo module'

import {name} from './module.js'
// 匯出多個
var names = 'names';
function hello(){
    console.log('hello')
}
class Person{}
export {name,hello,Person}

//匯出從命名
export {
    name as fooName
}
import {fooName} from './module.js'

// defalut 關鍵詞
export {
    name as default  // 預設匯出成員
} 
import {default as fooName} from './module.js'  // 引入時候需要從命名

export default name // 會將 name 作為當前模組的預設匯出
import fooName from './module.js' // 直接接受模組匯出的預設成員,可隨意取名fooName

注意項

var name = 'kack'
var age = 18
var obj = {name,age}
export {name,age}  //匯出的不是字面量物件,引入時候不是物件結構,匯出的是對應的引用關係

// 如果匯出物件,需要使用 export default ,之後可跟物件或者變數
export default {name,age}

import 的用法

import {name} from './module.js'

// from 後跟的必須是完整的路徑,不能節省副檔名
console.log(name)
// 打包工商使用時才可省略副檔名
//  ./ 路徑不可省略
// 或者完整的路徑
import {names} from 'http://loaclhost:3000/import.js' 

// 只執行而不是提取某個成員,{}可為空
import {} from './module'
// 獲取所有的匯出成員 ,通過as 放在特殊成員之中
import * as obj from  './require'
console.log(obj)

// import 只能出現在頂層,不能被包裹在作用域內
if(true){
    import {name} from './require' //錯誤
}
// 只能通過匯入函式方式,動態載入模組
import('./require') // 返回一個promise
.then(res=>console.log(res))

// 匯入default需要重新命名
import {name ,age, default as newName} from './require'
// 或者
import newName,{name ,age} from './require'

匯出匯入成員
例如專案中多個元件,可以新建一個公共部分接受所有成員,匯出
使用時節省匯出

import {Button, Avatar} from './components.js'

瀏覽器環境 Polyfill
Polyfill相容方案
是一個ES Module 的loader

npm install browser-es-module-loader


引入網頁中
<script src="dist/babel-browser-build.js"></script>
<script src="dist/browser-es-module-loader.js"></script>

ES Module in Node.js 支援情況
node版本>8.5
node環境可以直接原生方式實現

ES Module CommonJS

common.js
CommonJS 只能匯出一個預設成員
    module.exports = {foo:'commonjs'}
    exports.foo = 'commonjs'
    
    //node原生 commonJS 不允許通過require 方式載入 ES Module

module.js

ES Module 中可以匯入 CommonJS 模組
import mod from './common.js'
console.log(mod) //可以

不能直接提取成員,import不是對匯出成員的結構
import {mod} from './common.js'
console.log(mod) //失敗
  • ES Module 中可以匯入 CommonJS模組
  • CommonJS 中不能匯入 ES Module
  • CommonJS 始終只會匯出一個預設成員
  • 注意import不是結構匯出物件