前端模块化小记

207 阅读3分钟

简述

模块是对携带某些功能的代码的封装,有利于代码的解耦和复用,数据和实现存在于模块作用域,向外暴露一些变量或函数; 目前前端模块化相关的规范有AMD、CMD、CommonJS、ESModule

AMD-require.js和CMD-sea.js

AMD-require.js

AMD是RequireJS在推广过程中对模块定义的规范 AMD异步加载模块,用define定义模块、require引入模块、return暴露模块,用于浏览器环境

定义模块:define

// 定义没有依赖的模块
define(function(){
    return 模块
})

// 定义有依赖的模板
define(['module1', 'module2'], function(m1, m2){
    return 模板
})

引入模块:require

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

定义和暴露模块:return

define(['module1'], function(m1) {
    let name = 'pdx'
    function showName() {
        console.log('showName', name)
    }
    // 暴露模块
    return { showName }
})

CMD-sea.js

CMD是SeaJS在推广过程中对模块定义的规范 CMD异步加载模块,用define定义模块、require引入模块、export暴露模块,用于浏览器环境,模块在使用时才会加载执行

引入、定义和暴露模块:

define(function(require, exports, module) {
    const module1 = require('./module1')
    const showName = function () {
        console.log('name: pdx')
    }
    export.showName = showName
})

CMD与AMD区别

1.定义模块处理依赖方式不同,AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块;CMD推崇就近依赖,只有在用到某个模块的时候再去加载

2.都是异步加载模块,但是AMD加载完模块后立刻执行,而CMD是等所有依赖都加载完后才执行(这是AMD用户体验好、CMD性能好的原因)

CommonJS

Node就是采用CommonJS模块规范,不过目前还是盛行ESM,Node很多源码也是改成ESM

CommonJS模块特点: 1.所有代码运行在模块作用域内,不会污染全局变量

2.模块是同步加载

3.模块首次执行后会缓存,再次加载获取的是缓存结果

4.CommonJS输出是值的拷贝,也就是说require返回的值是被输出的值的拷贝,模块内部的变化也不会影响这个值(加载机制)

// a.js
var num = 1
function reduceNum() {
  num++;
}
module.exports = {
  num: num,
  reduceNum: reduceNum
};
// main.js
var num = require('./a.js').num;
var reduceNum = require('./a.js').reduceNum;

console.log(num); // 1
reduceNum()
console.log(num); // 1

引入模块:require

var dayjs = require('day.js')

暴露模块:export

var name = 'pdx'
module.export.name = name
// 或者
export.name = name

ESModule

ES6 Module的设计思想是尽量的静态化(在此简称ESM或ESModule),使得编译时就能去确定模块的依赖关系,以及输入和输出的变量 CommonJS和AMD都是运行时才确定依赖关系。比如CommonJS模块就是对象,输入时必须查找对象属性。

import引入、export暴露

var add = function (val) {
    return val++
}
export { add }
import { add } from './add.js'
var age = 1;
add(age)
console.log('age:', age) // 2

使用import命令时,需要引入正确的变量名或函数名;如果使用export default,则import时可以自定义名字 加载机制:动态引用

// a.js
var num = 1
function reduceNum() {
  num++;
}
exports {
  num,
  reduceNum
};
// main.js
import { num, reduceNum } from './a.js'

console.log(num); // 1
reduceNum()
console.log(num); // 2

ESModule与CommonJS区别

1.CommonJS模块输出的是一个值的拷贝,而ESM模块输出的是值的引用

2.CommonJS模块时运行时加载,而ESM模块是编译时输出接口