概况

项目变大时需要把不同的业务分割成多个文件,这就是模块的思想。模块是比对象与函数更大的单元,使用模块组织程序便于维护与扩展。

在ES6之前,JavaScript一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。这对开发大型的、复杂的项目形成了障碍。

为了解决这个问题,创造了一些模块加载方案(如用于服务器的CommonJS,用于浏览器的AMD、CMD),各个方案各有自己的特点,并且语法还不一样,如果是要同时做前后端,那真的是会“精分”了。

好消息是ES6给我们带来了模块化的设计!这完全可以取代CommonJS、AMD等规范,成为浏览器和服务器通用的模块解决方案。

模块功能主要由两个命令构成:export 和 importexport 命令用于规定模块的对外接口,import 命令用于输入其他模块提供的功能。

下面通过定义一个类似 require.js 的 AMD 模块管理引擎,来体验模块的工作原理。
    <script>
      let module = function() {
        // 模块列表集合
        let moduleLists = {};
        function define(name, modules, action) {
          modules.map((m, i) => {
            modules[i] = moduleLists[m];
          });
          moduleLists[name] = action.apply(null, modules);
        }
        return { define , moduleLists };
      }();
      module.define("show",[],function(){
          return {
              show() {
                  console.log('show module')
              }
          }
      })
      module.define('myMath',[],function(){
          return {
              Max(arr, key) {
                  return arr.sort((a, b) => b[key] - a[key])[0]
              }
          }
      })
      module.define('xj',['show'],function(show){
        show.show()
      })
      module.define('compute',['myMath'],function(myMath){
          let data = [
              {name:'js', price:180},
              {name:'css', price:60}
            ];
        console.log(myMath.Max(data,'price'))
      })
    </script>

常见问题

图片说明
模块01.js开放了title,那么在其他模块中就可以使用title了,url是使用不了的
但是存在一个问题是如果你像下面这样写的话浏览器是会报错的
图片说明
报错如下:
图片说明

因为受到浏览器加载规则的限制,浏览器加载ES6模块,也是使用标签,但注意,需要加上 type="module" 属性。
可以有两种方法
1. 通过<script src="">加载js脚本

2.直接使用<script>标签内嵌js代码
但是加上以后虽然加载规则的问题解决了,但是还是出现了新的问题,如果使用(作者现在)火狐浏览器是可以直接打开HTML成功加载模块的,但是用Chrome就不行,报错如下
 图片说明
这并不是Chrome不支持加载模块,而是ES6模块遵循同源策略。解决方法就是打开本地服务器,让各个文件同源就可以了。
解决方法:
在本地使用node建立一个服务器


let path = require('path')
let express = require('express')

var app = express()

app.use(express.static(path.join(__dirname,'./')))

app.listen(8080, () => {
    console.log(`App listening at port 8080`)
})
在Chrome浏览器地址栏中输入对应的地址就可以正确访问了,因为两个文件处于一个服务器,浏览器就不会报非同源限制的错误
接着就可以在浏览器控制台上看到打印的结果了


模块的延迟解析

一般情况下解析的顺序是从上到下,但是在模块中不同
模块总是会在所有html解析后才执行,下面的模块代码可以看到后加载的 button 按钮元素。  
建议为用户提供加载动画提示,当模块运行时再去掉动画
<body>
  <script type="module">
    console.log(document.querySelector("button")); //Button
  </script>
  <script>
    console.log(document.querySelector("button")); //undefined
  </script>
  <button>按钮</button>
</body> 

模块默认运行在严格模式下

如果模块里面书写的不是严格模式会报错

模块作用域

模块都有独立的顶级作用域,不同模块之间不能互相访问
<script type="module">
  let hd = " niuke.com";
</script>

<script type="module">
  alert(niuke); // Error
</script>



模块的预解析

模块在导入时只执行一次解析,之后的导入使用第一次解析结果,并共享数据。