美文网首页
js模块化

js模块化

作者: koala949 | 来源:发表于2020-11-22 22:00 被阅读0次

    早期将js代码放入不同的文件里面,通过多个srcipt标签来加载他们

    <script src='./a.js'></script>

    虽然每个代码块出在不同的文件中,但最终所有的js变量还是会处在全局作用域下,就需要额外注意由于作用域变量提升所带来的问题。如果代码之间有依赖关系,则需额外注意脚本加载的顺序。
    为解决这样的问题,我们需要将这些脚本文件模块化:

    • 每个模块有自己的变量作用域
    • 不同模块之间保留相互导入和导出的方式方法。

    commonJs规范初探

    nodejs就是一个基于V8引擎,事件驱动I/O的服务端js运行环境,在09年刚推出时,就实现了一套CommomJs的模块化规范

    每个js就是一个模块(module,每个模块内部使用require函数和module.exports对象对模块进行导入导出
    在不同的模块加载moduleB两次,会得到相同的结果,这说明他保证了模块单例。
    commonJs是一个同步加载模块的模块化规范,每当一个模块require一个子模块时,都会停止当前模块的解析直到子模块读取解析并加载

    适合web开发的AMD模块化规范

    asynchronous module definition 意为 异步模块定义,因为如果在浏览器中也使用同步加载,那么页面在解析脚本文件的过程中可能会使页面暂停响应。

    AMD规范举例

    // index.js
    // require函数第一个参数是 入口模块的依赖列表, 第二个参数作为回调函数依次传入前面依赖的导出值,不同于CommonJS的是,这个回调函数的返回值即时模块导出结果
    
    require(['moduleA','moduleB'], function (moduleA, moduleB){
      console.log(moduleB)
    })
    
    // moduleA.js
    define(function(require){
      var  = require('moduleB')
      setTimeOut(() => console.log(m), 1000)
    })
    
    // moduleB.js
    define(function(require){
       var m = new Data().getTime();
       return m
    })
    

    Nodejs里直接通过node index.js可查看输出结果,在web端我们需要一个html文件,同时在里面加载这个入口模块, 如果想使用AMD规范, 还需要在页面中添加符合AMD规范的加载器脚本

    <script src="/require.js"></script>

    直接起到服务器里命令

    python -m SimpleHTTPServer 8080

    从结果上来说 AMD和CommonJs一样,完美解决了变量作用域和依赖关系之类的问题,但是这种AMD默认异步, 在回调函数中定义模块内容, 相对来说使用就麻烦些。
    同时, AMD的模块不能直接运行在node端,因为内部的define函数,require函数都必须配合在浏览器中加载require.js这类ADM库才能使用。

    能同时被CommonJs规范和AMD规范加载的UMD模块

    有时候我们希望写的模块能同时运行在浏览区端和NodeJs里,使用UMD(universal module definition)作为一种同构的模块化解决方案,在一个地方定义模块内容,同时兼容ADM和CommonJS规范

    需要判断一下这些模块化规范的特征值,判断出当前究竟在哪种模块化规范的环境下,然后把模块内容用检测出的模块化规范的语法导出

    // 写法不固定
    (function(self, factory){
       if(typeof module === 'object' && typeof module.exports === 'object'){
       module.exports  = factory()
    } else if ( typeof define === 'function' && define.amd){
      define(factory)
    } else {
      // 什么环境也不是,直接挂在全局对象上
      self.umdModule = factory()
    }
    })( this, factory){
       return function(){
         retrun Math.randow()
      }
    }
    

    ESModule规范

    es6之后,js有了语言层面的模块化导入导出关键词和语法以及匹配的esModule规范。
    示例:

    // index.js
    import './moduleA';
    import m from './moduleB'
    console.log(m)
    
    
    //moduleA.js
    import m from './moduleB'
    setTimeOut(()=> console.log(m), 1000)
    
    // moduleB.js
      var m = new Data().getTime();
      export default m
    
    
    // import { var1 as customVar } from './moduleA'
    
    // 以下用法合理 因为commonJs导出的就是个对象
    const { var1 = 1} = require('./moduleA')
    const { [test]: var1: a} = require('./moduleA')
    
    

    每个js运行环境都有一个解析器,他的作用就是用ECAMScript规范去解释js语法,也就是处理和执行语言本身的内容。在解析器上层,每个运行环境都会在解释器的基础上封装一些环境相关的API。

    esModule是高版本工具,需要使用babel转义,对于模块化的importexport关键字,bebal最终会将他编译为包含require和export的commonJs规范,这就造成了另外一个问题, 这些关键字编译之后无法运行在浏览器中, 我们还需要一个步骤 打包,比如打包工具webpack/rollup,这样编译工具babel和他们的区别和作用就清楚了

    • 打包工具主要处理的是js不同版本间模块化的区别
    • 编译工具主要是处理JS版本间语义的问题

    如果使用了ESModule:必须使用webpack和babel
    如果是AMD或CommonJs:只用webpack

    相关文章

      网友评论

          本文标题:js模块化

          本文链接:https://www.haomeiwen.com/subject/ytxpiktx.html