写在前面的
记得没工作那会儿,我还是通过 script 标签引入相应的脚本文件,来实现或使用相应的功能。那个时候的我,就发现这个脚本文件引入顺序呀、引入数量呀等等都会带来一系列的问题。直至工作后,才慢慢开始对前端模块化有了一些概念。也理解了自己之前发现的这些问题,早就已被大佬们提出并给出相应的解决方式。
一、模块化标准
1. CommonJS
-
概述:
Node 应用由模块组成,通俗的说就是用 npm 安装的模块,采用 CommonJS 模块规范。每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。 -
语法:
暴露模块:module.exports = value
或exports.key = value
引入模块:require(xxx)
-
模块的加载机制:
输入的是被输出的值的拷贝。也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。// lib.js var counter = 3; function incCounter() { counter++; } module.exports = { counter: counter, incCounter: incCounter, }; //复制代码上面代码输出内部变量counter和改写这个变量的内部方法 incCounter。 // main.js var counter = require('./lib').counter; var incCounter = require('./lib').incCounter; console.log(counter); // 3 incCounter(); console.log(counter); // 3
2. AMD(Asynchronous Module Definition)
-
概述:
异步模块定义,所谓异步是指模块和模块的依赖可以被异步加载,他们的加载不会影响它后面语句的运行。有效避免了采用同步加载方式中导致的页面假死现象。AMD代表:RequireJS。 -
语法:
暴露模块:
引入模块define(id?, dependencies?, factory); //id :可选参数,它指的是模块的名字。 //dependencies:可选参数,定义中模块所依赖模块的数组。 //factory:模块初始化要执行的函数或对象 define("alpha", ["require", "exports", "beta"], function (require, exports, beta) { exports.verb = function() { return beta.verb(); //Or: //return require("beta").verb(); } });
require([module], callback); //module:一个数组,里面的成员就是要加载的模块. //callback:模块加载成功之后的回调函数。 require(["a","b","c"],function(a,b,c){ //code here });
3. CMD(Common Module Definition)
-
概述:
CMD 规范专门用于浏览器端,模块的加载是异步的,模块使用时才会加载执行。CMD 规范整合了 CommonJS 和 AMD 规范的特点。在 Sea.js 中,所有 JavaScript 模块都遵循 CMD 模块定义规范。 -
语法:
定义暴露模块://定义没有依赖的模块 define(function(require, exports, module){ // require: 一个方法标识符,调用它可以动态的获取一个依赖模块的输出 // exports: 一个对象,用于对其他模块提供输出接口,例如:exports.name = "xxx" // module: 一个对象,存储了当前模块相关的一些属性和方法,其中module.exports属性等同于上面的exports exports.xxx = value module.exports = value }) //定义有依赖的模块 define(function(require, exports, module){ //引入依赖模块(同步) var module2 = require('./module2') //引入依赖模块(异步) require.async('./module3', function (m3) { }) //暴露模块 exports.xxx = value })
引入使用模块:
define(function (require) { var m1 = require('./module1') var m4 = require('./module4') m1.show() m4.show() })
-
优点:依赖就近,延迟执行 可以很容易在 Node.js 中运行;
缺点:依赖 SPM 打包,模块的加载逻辑偏重;
4. UMD
-
概述:
类似于兼容 CommonJS 和 AMD 的语法糖,是模块定义的跨平台解决方案。
5. ES6 模块
-
概述:
ES6模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。所以说ES6是编译时加载 -
语法:
export
命令用于规定模块的对外接口,import
命令用于输入其他模块提供的功能。
为了给用户提供方便,就要用到// math.js var basicNum = 0; var add = function (a, b) { return a + b; }; export { basicNum, add }; // 引用模块 import { basicNum, add } from './math'; function test(ele) { ele.textContent = add(99 + basicNum); }
export default
命令,为模块指定默认输出。// export-default.js export default function () { console.log('foo'); } // import-default.js import customName from './export-default'; customName(); // 'foo'
-
模块的加载机制:
ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。// lib.js export let counter = 3; export function incCounter() { counter++; } // main.js import { counter, incCounter } from './lib'; console.log(counter); // 3 incCounter(); console.log(counter); // 4
网友评论