了解(所有)“模块化” JavaScript格式和工具



朋友们,美好的一天!

我向您介绍Dixin 撰写的文章“了解(所有)JavaScript模块格式和工具”

在创建应用程序时,通常希望将代码分为部分,逻辑或功能块(模块)。但是,JavaScript最初没有模块支持。这导致了各种模块化技术的出现。本文讨论了在JavaScript中使用模块的所有基本概念,模板,库,语法和工具。


IIFE模块:JS模块模板


通过在JS中定义变量,我们将其定义为全局变量。这意味着该变量将在当前页面上加载的所有JS文件中可用:

    //   
    let count = 0
    const increase = () => ++count
    const reset = () => {
        count = 0
        console.log(' .')
    }

    //   
    increase()
    reset()

为了避免污染全局名称空间,可以使用匿名函数:

    (() => {
        let count = 0
        // ...
    })

瞧,没有更多的全局变量了。但是,该函数内部的代码未执行。

IIFE:立即函数表达


为了在函数内部执行代码f,必须使用()how 来调用它f()要在匿名函数内部执行代码,(() => {})也应使用()看起来像这样(() => {})()

    (() => {
        let count = 0
        // ...
    })()

这称为IIFE(立即称为函数表达式)。一个模块可以定义如下:

    //  IIFE 
    const iifeCounterModule = (() => {
        let count = 0
        return {
            increase: () => ++count,
            reset: () => {
                count = 0
                console.log(' .')
            }
        }
    })()

    //  IIFE 
    iifeCounterModule.increase()
    iifeCounterModule.reset()

我们将模块代码包装在IIFE中。匿名函数返回一个对象。这将替换导出接口。仅有一个全局变量-模块的名称(或其名称空间)。随后,可以使用模块的名称来调用它(导出)。这称为JS模块模板。

进口杂质


定义模块时,可能需要一些依赖关系。使用模块化模板时,每个从属模块都是全局变量。依赖模块可以在匿名函数中定义,也可以作为参数传递给它:

    //  IIFE   
    const iifeCounterModule = ((dependencyModule1, dependencyModule2) => {
        let count = 0
        return {
            increase: () => ++count,
            reset: () => {
                count = 0
                console.log(' .')
            }
        }
    })(dependencyModule1, dependencyModule2)

流行的库(例如jQuery)的早期版本使用了此模板(jQuery的最新版本使用了UMD模块)。

打开模块:打开JS模块模板


开放模块模板由Christian Heilmann创造。该模板也是IIFE,但是重点在于将所有接口定义为匿名函数内的局部变量:

    //   
    const revealingCounterModule = (() => {
        let count = 0
        const increase = () => ++count
        const reset = () => {
            count = 0
            console.log(' .')
        }

        return {
            increase,
            reset
        }
    })()

    //   
    revealingCounterModule.increase()
    revealingCounterModule.reset()

此语法使您更容易理解每​​个接口负责什么(或其作用)。

CJS模块:CommonJS模块或Node.js模块


CommonJS(最初称为ServerJS)是用于定义和使用模块的模板。它内置在Node.js中。默认情况下,每个JS文件都是一个CJS。变量moduleexports提供模块(文件)的导出。该功能require提供了加载和使用模块的功能。以下代码演示了CommonJS语法中计数器模块的定义:

    //  CommonJS : commonJSCounterModule.js
    const dependencyModule1 = require('./dependencyModule1')
    const dependencyModule2 = require('./dependencyModule2')

    let count = 0
    const increase = () => ++count
    const reset = () => {
        count = 0
        console.log(' .')
    }

    exports.increase = increase
    exports.reset = reset
    //  ()
    module.exports = {
        increase,
        reset
    }

这是使用此模块的方式:

    //  CommonJS 
    const {
        increase,
        reset
    } = require('./commonJSCounterModule')
    increase()
    reset()
    // 
    const commonJSCounterModule = require('./commonJSCounterModule')
    commonJSCounterModule.increase()
    commonJSCounterModule.reset()

在Node.js运行时(引擎)中,通过将文件内的代码包装到一个函数中来使用此模板,变量exports, module和函数作为参数传递给该函数require

    //  CommonJS 
    (function(exports, require, module, __filename, __dirname) {
        const dependencyModule1 = require('./dependencyModule1')
        const dependencyModule2 = require('./dependencyModule2')

        let count = 0
        const increase = () => ++count
        const reset = () => {
            count = 0
            console.log(' .')
        }

        module.exports = {
            increase,
            reset
        }

        return module.exports
    }).call(thisValue, exports, require, module, filename, dirname)

    //  CommonJS 
    (function(exports, require, module, __filename, __dirname) {
        const commonJSCounterModule = require('./commonJSCounterModule')
        commonJSCounterModule.increase()
        commonJSCounterModule.reset()
    }).call(thisValue, exports, require, module, filename, dirname)

AMD模块或RequireJS模块


AMD(异步模块定义)是用于定义和使用模块的模板。它在RequireJS库中使用AMD包含一个define模块定义函数,该函数接受模块名称,依赖项名称和工厂功能:

    //  AMD 
    define('amdCounterModule', ['dependencyModule1', 'dependencyModule2'], (dependencyModule1, dependencyModule2) => {
        let count = 0
        const increase = () => ++count
        const reset = () => {
            count = 0
            console.log(' .')
        }

        return {
            increase,
            reset
        }
    })

它还包含require使用模块的功能

    //  AMD 
    require(['amdCounterModule'], amdCounterModule => {
        amdCounterModule.increase()
        amdCounterModule.reset()
    })


requireAMD与requireCommonJS的不同之处在于,它以模块的名称和模块本身作为函数的参数。

动态加载


功能define也有不同的用途。它需要一个回调函数,并将类似于CommonJS的require函数传递给该函数。在回调函数中,调用require来动态加载模块:

    //   AMD 
    define(require => {
        const dynamicDependencyModule1 = require('dependencyModule1')
        const dynamicDependencyModule2 = require('dependencyModule2')

        let count = 0
        const increase = () => ++count
        const reset = () => {
            count = 0
            console.log(' .')
        }

        return {
            increase,
            reset
        }
    })

来自CommonJS模块的AMD模块


上述功能define,此外require,可以采取的变量exports作为参数module因此,define来自CommonJS的代码可以在内部执行:

    //  AMD   CommonJS 
    define((require, exports, module) => {
        // CommonJS 
        const dependencyModule1 = require('dependencyModule1')
        const dependencyModule2 = require('dependencyModule2')

        let count = 0
        const increase = () => ++count
        const reset = () => {
            count = 0
            console.log(' .')
        }

        exports.increase = increase
        exports.reset = reset
    })

    //  AMD   CommonJS 
    define(require => {
        // CommonJS 
        const counterModule = require('amdCounterModule')
        counterModule.increase()
        counterModule.reset()
    })

UMD模块:通用模块定义或UmdJS模块


UMD(通用模块定义)-一组模板,用于确保模块在不同运行时环境中的运行。

适用于AMD的UMD(RequireJS)和浏览器


以下代码在AMD(RequireJS)和浏览器中都提供了该模块:

    //  UMD   AMD (RequireJS)  
    ((root, factory) => {
        //   define AMD/RequireJS
        if (typeof define === 'function' && define.amd) {
            //  ,      
            define('umdCounterModule', ['dependencyModule1', 'dependencyModule2'], factory)
        } else {
            //  ,    
            //      (  Window)
            //    
            root.umdCounterModule = factory(root.dependencyModule1, root.dependencyModule2)
        }
    })(typeof self !== undefined ? self : this, (dependencyModule1, dependencyModule2) => {
        //  
        let count = 0
        const increase = () => ++count
        const reset = () => {
            count = 0
            console.log(' ')
        }

        return {
            increase,
            reset
        }
    })

看起来很复杂,但这只是IIFE。匿名函数确定是否有define来自AMD / RequireJS 的函数

  • 如果define检测到,则通过它调用工厂函数。
  • 如果define未找到,则直接调用工厂函数。此时,参数root是浏览器的Window对象。它从全局变量(Window对象的属性)接收从属模块。factory模块返回时,它也成为全局变量(Window对象的属性)。

适用于AMD(RequireJS)和CommonJS(Node.js)的UMD


以下代码在AMD(RequireJS)和CommonJS(Node.js)中提供了该模块:

    (define => define((require, exports, module) => {
        //  
        const dependencyModule1 = require("dependencyModule1")
        const dependencyModule2 = require("dependencyModule2")

        let count = 0
        const increase = () => ++count
        const reset = () => {
            count = 0
            console.log("Count is reset.")
        }

        module.export = {
            increase,
            reset
        }
    }))( //   module  exports  CommonJS/Node.js
        //    define  AMD/RequireJS
        typeof module === 'object' && module.exports && typeof define !== 'function'
            ? // CommonJS/Node.js.    define
                factory => module.exports = factory(require, exports, module)
            : // AMD/RequireJS.   define
                define)

别担心,这只是IIFE。调用匿名函数时,其参数为“求值”。评估参数以确定执行环境(由变量moduleexportsCommonJS / Node.js 的存在以及defineAMD / RequireJS 的功能定义)。

  • 如果运行时是CommonJS / Node.js,则匿名函数参数将手动创建function define
  • 如果运行时是AMD / RequireJS,则匿名函数的参数是define该环境中的函数执行匿名功能可确保该功能正常工作define在匿名函数内部,将调用一个函数来创建模块define

ES模块:ECMAScript2015或ES6模块


2015年,JS规范的版本6引入了新的模块化语法。这称为ECMAScript 2015(ES2015)或ECMAScript 6(ES6)。新语法的基础是关键字importand export以下代码演示了将ES模块用于命名和默认(默认)导入/导出的用法:

    //  ES : esCounterModule.js  esCounterModule.mjs
    import dependencyModule1 from './dependencyModule1.mjs'
    import dependencyModule2 from './dependencyModule2.mjs'

    let count = 0
    //  
    export const increase = () => ++count
    export const reset = () => {
        count = 0
        console.log(' .')
    }
    //    
    export default {
        increase,
        reset
    }

要在浏览器中使用模块文件,请添加标签<script>并将其标识为模块:<script type="module" src="esCounterModule.js"></script>要在Node.js中使用此模块,请将其扩展名更改为.mjs

    //  ES 
    //    
    import {
        increase,
        reset
    } from './esCounterModule.mjs'
    increase()
    reset()
    //      
    import esCounterModule from './esCounterModule.mjs'
    esCounterModule.increase()
    esCounterModule.reset()


为了在浏览器中向后兼容,您可以添加<script>带有属性的标签nomodule

    <脚本nomodule>
        警报(“不支持。”)
    </ script>

ES动态模块:ECMAScript2020或ES11动态模块


JS 2020规范的最新11版本引入了import用于动态使用ES模块的内置功能该函数返回一个Promise,因此您可以将模块用于then

    //   ES    ,    
    import('./esCounterModule.js').then(({
        increase,
        reset
    }) => {
        increase()
        reset()
    })
    //      
    import('./esCounterModule.js').then(dynamicESCounterModule => {
        dynamicESCounterModule.increase()
        dynamicESCounterModule.reset()
    })

由于该函数import返回promise,因此可以使用关键字await

    //   ES   async/await
    (async () => {
        //    
        const {
            increase,
            reset
        } = await import('./esCounterModule.js')
        increase()
        reset()

        //      
        const dynamicESCounterModule = await import('./esCounterModule.js')
        dynamicESCounterModule.increase()
        dynamicESCounterModule.reset()
    })

系统模块:SystemJS模块


SystemJS是一个库,用于在旧版浏览器中支持ES模块。例如,以下模块是使用ES6语法编写的:

    //  ES 
    import dependencyModule1 from "./dependencyModule1.js"
    import dependencyModule2 from "./dependencyModule2.js"
    dependencyModule1.api1()
    dependencyModule2.api2()

    let count = 0
    //  
    export const increase = function() {
        return ++count
    }
    export const reset = function() {
        count = 0
        console.log("Count is reset.")
    }
    //    
    export default {
        increase,
        reset
    }

该代码在不支持ES6语法的浏览器中不起作用。解决此问题的一种方法是使用System.registerSystemJS库接口转换代码

    //  SystemJS 
    System.register(['./dependencyModule1', './dependencyModule2'], function(exports_1, context_1) {
        'use strict'
        var dependencyModule1_js_1, dependencyModule2_js_1, count, increase, reset
        var __moduleName = context_1 && context_1.id
        return {
            setters: [
                function(dependencyModule1_js_1_1) {
                    dependencyModule1_js_1 = dependencyModule1_js_1_1
                },
                function(dependencyModule2_js_1_1) {
                    dependencyModule2_js_1 = dependencyModule2_js_1_1
                }
            ],
            execute: function() {
                dependencyModule1_js_1.default.api1()
                dependencyModule2_js_1.default.api2()
                count = 0
                //  
                exports_1('increase', increase = function() {
                    return ++count
                })
                exports_1('reset', reset = function() {
                    count = 0
                    console.log(' .')
                })
                //    
                exports_1('default', {
                    increase,
                    reset
                })
            }
        }
    })

新的模块化ES6语法已消失。但是该代码在较旧的浏览器中可以正常工作。可以使用Webpack,TypeScript等自动完成此转换。

动态模块加载


SystemJS还包含import用于动态导入的功能

    //  SystemJS   
    System.import('./esCounterModule.js').then(dynamicESCounterModule => {
        dynamicESCounterModule.increase()
        dynamicESCounterModule.reset()
    })

Webpack模块:CJS,AMD和ES模块的编译和组装


Webpack是一个模块构建器。它的编译器将CommonJS,AMD和ES模块组合到一个平衡的模块化模板中,并将所有代码收集到一个文件中。例如,在以下3个文件中,使用不同的语法定义了3个模块:

    //  AMD : amdDependencyModule1.js
    define('amdDependencyModule1', () => {
        const api1 = () => {}
        return {
            api1
        }
    })

    //  CommonJS : commonJSDependencyModule2.js
    const dependencyModule2 = require('./commonJSDependencyModule2')
    const api2 = () => dependencyModule1.api1()
    exports.api2 = api2

    //  ES : esCounterModule.js
    import dependencyModule1 from './amdDependencyModule1'
    import dependencyModule2 from './commonJSDependencyModule2'

    let count = 0
    const increase = () => ++count
    const reset = () => {
        count = 0
        console.log(' .')
    }

    export default {
        increase,
        reset
    }

以下代码演示了此模块的用法:

    //  ES : index.js
    import counterModule from './esCounterModule'
    counterModule.increase()
    counterModule.reset()

Webpack能够将这些文件(尽管它们是不同的模块化系统)组合到一个文件中main.js


        dist
            main.js(位于src文件夹中的文件的汇编)
        src
            amdDependencyModule1.js
            commonJSDependencyModule2.js
            esCounterModule.js
            index.js
        webpack.config.js

由于Webpack基于Node.js,因此它使用CommonJS的模块化语法。webpack.config.js

    const path = require('path')

    module.exports = {
        entry: './src/index.js',
        mode: 'none', //          
        output: {
            filename: 'main.js',
            path: path.resolve(__dirname, 'dist'),
        },
    }

要编译和构建,必须运行以下命令:

    npm安装webpack webpack-cli --save-dev
    npx webpack --config webpack.config.js

结果,Webpack将创建文件main.jsmain.js格式化以下代码以提高可读性:

    (function(modules) { //  Webpack
        //    
        var installedModules = {}
        //  require
        function require(moduleId) {
            // ,     
            if (installedModules[moduleId]) {
                return installedModules[moduleId].exports
            }
            //        
            var module = installedModules[moduleId] = {
                i: moduleId,
                l: false,
                exports: {}
            }
            //   module
            modules[moduleId].call(module.exports, module, module.exports, require)
            //    
            module.l = true
            //   exports 
            return module.exports
        }

        //   modules (__webpack_modules__)
        require.m = modules
        //    
        require.c = installedModules
        //     
        require.d = function(exports, name, getter) {
            if (!require.o(exports, name)) {
                Object.defineProperty(exports, name, {
                    enumerable: true,
                    get: getter
                })
            }
        }
        //  __esModule  exports
        require.r = function(exports) {
            if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
                Object.defineProperty(exports, Symbol.toStringTag, {
                    value: 'Module'
                })
            }
            Object.defineProperty(exports, '__esModule', {
                value: true
            })
        }
        //       
        // mode & 1:  -  ,  
        // mode & 2:       ns (namespace)
        // mode & 4:  ,   ns  
        // mode & 8|1:   require
        require.t = function(value, mode) {
            if (mode & 1) value = require(value)
            if (mode & 8) return value
            if ((mode & 4) && typeof value === 'object' && value && value.__esModule) return value
            var ns = Object.create(null)
            require.r(ns)
            Object.defineProperty(ns, 'default', {
                enumerable: true,
                value: value
            })
            if (mode & 2 && typeof value !== 'string')
                for (var key in value) require.d(ns, key, function(key) {
                    return value[key]
                }.bind(null, key))
            return ns
        }
        //  getDefaultExport      
        require.n = function(module) {
            var getter = module && module.__esModule ?
                function getDefault() {
                    return module['default']
                } :
                function getModuleExports() {
                    return module
                }
            require.d(getter, 'a', getter)
            return getter
        }
        // Object.prototype.hasOwnProperty.call
        require.o = function(object, property) {
            return Object.prototype.hasOwnProperty.call(object, property)
        }
        // __webpack_public_path__
        require.p = ''
        //      exports
        return require(require.s = 0)
    })([
        function(module, exports, require) {
            'use strict'
            require.r(exports)
            //  ES : index.js
            var esCounterModule = require(1)
            esCounterModule['default'].increase()
            esCounterModule['default'].reset()
        },
        function(module, exports, require) {
            'use strict'
            require.r(exports)
            //  ES : esCounterModule.js
            var amdDependencyModule1 = require.n(require(2))
            var commonJSDependencyModule2 = require.n(require(3))
            amdDependencyModule1.a.api1()
            commonJSDependencyModule2.a.api2()

            let count = 0
            const increase = () => ++count
            const reset = () => {
                count = 0
                console.log(' .')
            }

            exports['default'] = {
                increase,
                reset
            }
        },
        function(module, exports, require) {
            var result!(result = (() => {
                    //  AMD : amdDependencyModule1.js
                    const api1 = () => {}
                    return {
                        api1
                    }
                }).call(exports, require, exports, module),
                result !== undefined && (module.exports = result))
        },
        function(module, exports, require) {
            //  CommonJS : commonJSDependencyModule2.js
            const dependencyModule1 = require(2)
            const api2 = () => dependencyModule1.api1()
            exports.api2 = api2
        }
    ])

同样,这就是IIFE。4个文件中的代码将转换为4个函数的数组。并将此数组作为参数传递给匿名函数。

Babel模块:ES模块的翻译


Babel是另一个在较旧的浏览器中支持ES6 +代码的传输器。可以将上述ES6 +模块转换为Babel模块,如下所示:

    // Babel
    Object.defineProperty(exports, '__esModule', {
        value: true
    })
    exports['default'] = void 0

    function _interopRequireDefault(obj) {
        return obj && obj.__esModule ? obj : {
            'default': obj
        }
    }

    //  ES : esCounterModule.js
    var dependencyModule1 = _interopRequireDefault(require('./amdDependencyModule1'))
    var dependencyModule2 = _interopRequireDefault(require('./commonJSDependencyModule2'))
    dependencyModule1['default'].api1()
    dependencyModule2['default'].api2()

    var count = 0
    var increase = function() {
        return ++count
    }
    var reset = function() {
        count = 0
        console.log(' .')
    }

    exports['default'] = {
        increase: increase,
        reset: reset
    }

以下是中的代码index.js,演示了此模块的用法:

    // Babel
    function _interopRequireDefault(obj) {
        return obj && obj.__esModule ? obj : {
            'default': obj
        }
    }

    //  ES : index.js
    var esCounterModule = _interopRequireDefault(require('./esCounterModule.js'))
    esCounterModule['default'].increase()
    esCounterModule['default'].reset()

这是默认的转译。Babel还知道如何与其他工具一起使用。

Babel和SystemJS


SystemJS可以用作Babel的插件:

    npm install --save-dev @ babel /插件转换模块-systemjs


该插件应添加到babel.config.json

    {
        'plugins':['@ babel / plugin-transform-modules-systemjs'],
        '预设':[
            [
            '@ babel / env',
                {
                    “目标”:{
                        'ie':'11'
                    }
                }
            ]
        ]
    }

现在,Babel可以与SystemJS一起移植CommonJS / Node.js,AMD / RequireJS和ES模块:

    npx babel src --out-dir库

结果:


        LIB
            amdDependencyModule1.js(使用SystemJS进行翻译)
            commonJSDependencyModule2.js(使用SystemJS编译)
            esCounterModule.js(使用SystemJS进行翻译)
            index.js(使用SystemJS编译)
        src
            amdDependencyModule1.js
            commonJSDependencyModule2.js
            esCounterModule.js
            index.js
        babel.config.json

AMD,CommonJS和ES模块的整个语法都转换为SystemJS语法:

    //  AMD/RequireJS   SystemJS : lib/amdDependencyModule1.js
    System.register([], function(_export, _context) {
        'use strict'
        return {
            setters: [],
            execute: function() {
                //  AMD : src/amdDependencyModule1.js
                define('amdDependencyModule1', () => {
                    const api1 = () => {}

                    return {
                        api1
                    }
                })
            }
        }
    })

    //  CommonJS/Node.js   SystemJS : lib/commonJSDependencyModule2.js.
    System.register([], function(_export, _context) {
        'use strict'
        var dependencyModule1, api2
        return {
            setters: [],
            execute: function() {
                //  CommonJS : src/commonJSDependencyModule2.js
                dependencyModule1 = require('./amdDependencyModule1')

                api2 = () => dependencyModule1.api1()

                exports.api2 = api2
            }
        }
    })

    //  ES   SystemJS 
    System.register(['./amdDependencyModule1', './commonJSDependencyModule2'], function(_export, _context) {
        var dependencyModule1, dependencyModule2, count, increase, reset
        return {
            setters: [function(_amdDependencyModule) {
                dependencyModule1 = _amdDependencyModule.default
            }, function(_commonJSDependencyModule) {
                dependencyModule2 = _commonJSDependencyModule.default
            }],
            execute: function() {
                //  ES : src/esCounterModule.js
                dependencyModule1.api1()
                dependencyModule1.api2()
                count = 0

                increase = () => ++count

                reset = () => {
                    count = 0
                    console.log(' .')
                }

                _export('default', {
                    increase,
                    reset
                })
            }
        }
    })

    //  ES   SystemJS : lib/index.js
    System.register(['./esCounterModule'], function(_export, _context) {
        var esCounterModule
        return {
            setters: [function(_esCounterModule) {
                esCounterModule = _esCounterModule.default
            }],
            execute: function() {
                //  ES : src/index.js
                esCounterModule.increase()
                esCounterModule.reset()
            }
        }
    })

TypeScript模块:CJS,AMD,ES和SystemJS模块的转译


TypeScript支持所有形式的JS语法,包括ES6。期间transpilation,所述ES6模块的语法可以保存或转换为另一种格式,包括CommonJS的/ Node.js的,AMD / RequireJS,UMD / UmdJS或SystemJS根据transpilation中的设置tsconfig.json

    {
        'compilerOptions':{
            'module':'ES2020'//无,CommonJS,AMD,System,
            UMD,ES6,ES2015,ESNext
        }
    }

例如:

    // TypeScript  ES 
    //  compilerOptions: { module: 'ES6' }.    
    import dependencyModule from './dependencyModule'
    dependencyModule.api()
    let count = 0
    export const increase = function() {
        return ++count
    }

    //  compilerOptions: { module: 'CommonJS' }.   CommonJS/Node.js 
    var __importDefault = (this && this.__importDefault) || function(mod) {
        return (mod && mod.__esModule) ? mod : {
            'default': mod
        }
    }
    exports.__esModule = true

    var dependencyModule_1 = __importDefault(require('./dependencyModule'))
    dependencyModule_1['default'].api()
    var count = 0
    exports.increase = function() {
        return ++count
    }

    //  compilerOptions: { module: 'AMD' }.   AMD/RequireJS 
    var __importDefault = (this && this.__importDefault) || function(mod) {
        return (mod && mod.__esModule) ? mod : {
            'default': mod
        }
    }
    define(['require', 'exports', './dependencyModule'], function(require, exports, dependencyModule_1) {
        'use strict'
        exports.__esModule = true

        dependencyModule_1 = __importDefault(dependencyModule_1)
        dependencyModule_1['default'].api()
        var count = 0
        exports.increase = function() {
            return ++count
        }
    })

    //  compilerOptions: { module: 'UMD' }.   UMD/UmdJS 
    var __importDefault = (this & this.__importDefault) || function(mod) {
            return (mod && mod.__esModule) ? mod : {
                'default': mod
            }
        }
        (function(factory) {
            if (typeof module === 'object' && typeof module.exports === 'object') {
                var v = factory(require, exports)
                if (v !== undefined) module.exports = v
            } else if (typeof define === 'function' && define.amd) {
                define(['require', 'exports', './dependencyModule'], factory)
            }
        })(function(require, exports) {
            'use strict'
            exports.__esModule = true

            var dependencyModule_1 = __importDefault(require('./dependencyModule'))
            dependencyModule_1['default'].api()
            var count = 0
            exports.increase = function() {
                return ++count
            }
        })

    //  compilerOptions: { module: 'System' }.   System/SystemJS 
    System.register(['./dependencyModule'], function(exports_1, context_1) {
        'use strict'
        var dependencyModule_1, count, increase
        car __moduleName = context_1 && context_1.id
        return {
            setters: [
                function(dependencyModule_1_1) {
                    dependencyModule_1 = dependencyModule_1_1
                }
            ],
            execute: function() {
                dependencyModule_1['default'].api()
                count = 0
                exports_1('increase', increase = function() {
                    return ++count
                })
            }
        }
    })

TypeScript支持的模块化ES语法称为外部模块。

内部模块和命名空间


TypeScript也有关键字modulenamespace它们被称为内部模块:

    module Counter {
        let count = 0
        export const increase = () => ++count
        export const reset = () => {
            count = 0
            console.log(' .')
        }
    }

    namespace Counter {
        let count = 0
        export const increase = () => ++count
        export const reset = () => {
            count = 0
            console.log(' .')
        }
    }

两者都转置为JS对象:

    var Counter;
    (function(Counter) {
        var count = 0
        Counter.increase = function() {
            return ++count
        }
        Counter.reset = function() => {
            count = 0
            console.log(' .')
        }
    })(Counter || (Counter = {}))

TypeScript模块和名称空间可以通过分隔符具有多个嵌套级别.

    module Counter.Sub {
        let count = 0
        export const increase = () => ++count
    }

    namespace Counter.Sub {
        let count = 0
        export const increase = () => ++count
    }

子模块和子命名空间被转换为对象属性:

    var Counter;
    (function(Counter) {
        var Sub;
        (function(Sub) {
            var count = 0
            Sub.increase = function() {
                return ++count
            }
        })(Sub = Counter.Sub || (Counter.Sub = {}))
    })(Counter || (Counter = {}))

TypeScript模块和名称空间也可以在语句中使用export

    module Counter {
        let count = 0
        export module Sub {
            export const increase = () => ++count
        }
    }

    module Counter {
        let count = 0
        export namespace Sub {
            export const increase = () => ++count
        }
    }

上面的代码还转换为子模块和子命名空间:

    var Counter;
    (function(Counter) {
        var count = 0
        var Sub;
        (function(Sub) {
            Sub.increase = function() {
                return ++count
            }
        })(Sub = Counter.Sub || (Counter.Sub = {}))
    })(Counter || (Counter = {}))

结论


欢迎使用JS,它有10多种系统/调制格式/名称空间:

  • IIFE模块:JS模块模板
  • 打开模块:打开JS模块模板
  • CJS模块:CommonJS模块或Node.js模块
  • AMD模块:异步模块定义或RequireJS模块
  • UMD模块:通用模块定义或UmdJS模块
  • ES模块:ECMAScript2015或ES6模块
  • ES动态模块:ECMAScript2020或ES11动态模块
  • 系统模块:SystemJS模块
  • Webpack模块:CJS,AMD和ES模块的编译和组装
  • Babel模块:ES模块的翻译
  • TypeScript模块和名称空间

幸运的是,JS当前具有标准的内置工具,可与Node.js和所有现代浏览器支持的模块一起使用。对于较旧的浏览器,您可以使用新的模块化ES语法,并使用Webpack / Babel / SystemJS / TypeScript将其转换为兼容的语法。

感谢您的时间。我希望它花得很好。

All Articles