概况
项目变大时需要把不同的业务分割成多个文件,这就是模块的思想。模块是比对象与函数更大的单元,使用模块组织程序便于维护与扩展。
在ES6之前,JavaScript一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。这对开发大型的、复杂的项目形成了障碍。
为了解决这个问题,创造了一些模块加载方案(如用于服务器的CommonJS,用于浏览器的AMD、CMD),各个方案各有自己的特点,并且语法还不一样,如果是要同时做前后端,那真的是会“精分”了。
好消息是ES6给我们带来了模块化的设计!这完全可以取代CommonJS、AMD等规范,成为浏览器和服务器通用的模块解决方案。
模块功能主要由两个命令构成:export 和 import。export 命令用于规定模块的对外接口,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代码
这并不是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>
模块的预解析
模块在导入时只执行一次解析,之后的导入使用第一次解析结果,并共享数据。