模块化规范

279 阅读3分钟

一、使用script导入文件的问题

请求过多 依赖模糊 难以维护

二、常用的模块化规范

1. CommonJS

  • 应用实现 nodejs 运行时加载

社区方案,提供了服务器/浏览器的模块加载方案。非语言层面的标准。只能在运行时确定模块的依赖关系及输入/输出的变量,无法进行静态优化。

  • 说明: 每个文件都可当做一个模块 在服务器端:模块加载是运行时同步加载 在浏览器端 模块需要提前编译打包处理

  • 基本语法

    暴露模块

   module.exports= value
   exports.xxx = value
   模块暴露的本质 export对象

引入模块

    require(xxx)
    第三方模块 xxx为包名
    自定义模块 xxx为模块路径
    vue 项目中常用来导入图片等资源

cmmonJS模块的加载原理

CommonJS的一个模块,就是一个脚本文件。require命令第一次加载该脚本,就会执行整个脚本,然后在内存生成一个对象。

{
  id: '...',
  exports: { ... },
  loaded: true,
  ...
}

上面代码中,该对象的id属性是模块名,exports属性是模块输出的各个接口,loaded属性是一个布尔值,表示该模块的脚本是否执行完毕。其他还有很多属性,这里都省略了。(详细介绍参见《require() 源码解读》

以后需要用到这个模块的时候,就会到exports属性上面取值。即使再次执行require命令,也不会再次执行该模块,而是到缓存之中取值。

CommonJS模块的循环加载

CommonJS模块的重要特性是加载时执行,即脚本代码在require的时候,就会全部执行。CommonJS的做法是,一旦出现某个模块被"循环加载",就只输出已经执行的部分,还未执行的部分不会输出

详情请参考阮志峰日志

2. ES6 (重要)ESMAScript6+

  • 实现 浏览器端编译时加载

出 语言规格层面支持模块功能。支持编译时静态分析,便于JS引入宏和类型检验。动态绑定。

  • 说明 依赖模块需要编译打包处理 ,可以将es6语法打包成es5语法 处理兼容性。 使用babel将es6 编译为es5代码, 使用Browserify 编译打包js
  • 语法 导出
  // 多次导出
  export const xxx = ...
  // 单次导出
  export default {}

导入

import xxx form '路径'
import '路径'
// 一般导入动态路由
import()

ES6模块的循环加载

ES6模块的运行机制与CommonJS不一样,它遇到模块加载命令import时,不会去执行模块,而是只生成一个引用。等到真的需要用到时,再到模块里面去取值。

因此,ES6模块是动态引用,不存在缓存值的问题,而且模块里面的变量,绑定其所在的模块。请看下面的例子。

// m1.js
export var foo = 'bar';
setTimeout(() => foo = 'baz', 500);

// m2.js
import {foo} from './m1.js';
console.log(foo);
setTimeout(() => console.log(foo), 500);

上面代码中,m1.js的变量foo,在刚加载时等于bar,过了500毫秒,又变为等于baz

让我们看看,m2.js能否正确读取这个变化。

$ babel-node m2.js
bar
baz

上面代码表明,ES6模块不会缓存运行结果,而是动态地去被加载的模块取值,以及变量总是绑定其所在的模块。

这导致ES6处理"循环加载"与CommonJS有本质的不同。 ES6根本不会关心是否发生了"循环加载",只是生成一个指向被加载模块的引用,需要开发者自己保证,真正取值的时候能够取到值。

3. AMD 规范 (Asynchronous Module Definition)

  • 说明 异步模块定义 专门用于浏览器端 模块的加载是异步的
  • 基本语法 定义暴露模块 1)定义没有依赖的模块
define(function(){
    return 模块
})

2)定义有依赖的模块

define(['module1','module2'],function(m1,m2){
   return 模块
})

引入使用模块

require(['module1','module2'],function(m1,m2){
  使用 m1、m2
})

4. CMD (Common Module Definition)

阿里已出售 了解即可