前端模块化四种常见的规范

238 阅读3分钟

最近面试的时候被问到了前端模块化,我自己把模块化和组件化的概念整混淆了,回答的驴头不对马嘴。后来我细想了一下,我确实对前端模块化理解不深,最近学习了一段时间之后,把关于模块化的知识总结下来

CommonJS

先说第一种常见的CommonJS,这个是伴随着nodeJS一起出现的一种规范。在nodeJS中,一个文件就是一个模块,每个模块都有自己的作用域和私有属性和方法,外界是无法获取的。

//module.js
let a = 0
say:()=>{
    console.log(a+1)
}

module.exports = { a , say}

但是可以通过export属性来对外暴露属性。exports就像是一个快递员,在js模块中定义好各种属性和方法然后交给快递员exports 传递出去,别的模块需要用到的时候就用 require 方法获取快递员中的属性

let { a, say } = require('./module.js') 
或者 
let exports = require(./module.js)
console.log(exports.a) // 0 
exports.say() // 1

底下参数解释引用自作者:小黎也
链接:juejin.cn/post/684490…

  • 如果参数字符串以“/”开头,则表示加载的是一个位于绝对路径的模块文件。比如,require('/home/marco/foo.js')将加载/home/marco/foo.js。

  • 如果参数字符串以“./”开头,则表示加载的是一个位于相对路径(跟当前执行脚本的位置相比)的模块文件。比如,require('./circle')将加载当前脚本同一目录的circle.js。

  • 如果参数字符串不以“./“或”/“开头,则表示加载的是一个默认提供的核心模块(位于Node的系统安装目录中),或者一个位于各级node_modules目录的已安装模块(全局安装或局部安装)。大家还记得 module.paths 吧,这里就派上用场了。举例来说,脚本/home/user/projects/foo.js执行了require('bar.js')命令,Node会依据 module.paths 路径加上文件名称,依次搜索。 这样设计的目的是,使得不同的模块可以将所依赖的模块本地化。

  • 如果参数字符串不以“./“或”/“开头,而且是一个路径,比如require('example-module/path/to/file'),则将先找到example-module的位置,然后再以它为参数,找到后续路径。

  • 如果指定的模块文件没有发现,Node会尝试为文件名添加.js、.json、.node后,再去搜索。.js件会以文本格式的JavaScript脚本文件解析,.json文件会以JSON格式的文本文件解析,.node文件会以编译后的二进制文件解析。所以文件名的后缀可以省略。

  • 如果想得到require命令加载的确切文件名,使用require.resolve()方法。

AMD 和 CMD

这两个规范大体很相似 我们主要关注于使用时的异同\

定义都用define

这两个规范如果定义的模块 没有依赖 的话那就相同\

define(function () {
    var num = 0;
    var add = function (x, y) {
        return x + y;
    };
    return {
        add,
        num
    };
});

如果定义新模块有依赖,AMD 推崇依赖前置、提前执行,CMD推崇依赖就近、延迟执行
AMD:在定义时就把依赖模块提前引入

define(["a", "b", "c", function(a, b, c) { 
     // code
    
});

CMD:在需要用到的时候在引入

define(function(require, exports, module) {
    var a = require('./a'); //在需要时申明
    var b = require('./b');
    var c = require('./c');
    //code
});

引入模块

AMD 使用 require方法

require(['math'],function(math){
    let sum = math.add(1,1);
    console.log(sum)
});

CMD 使用 seajs.use方法

seajs.use(['math.js'], function(math){
    let sum = math.add(1,1);
});

ES6

定义 使用 export

可以用export来对外暴露属性,类似commonJS中的快递员,也可以用export default 方法,这样可以不用定义名称

//mymodule.js
let count = 0;
let add = function (a, b) {
    return a + b;
};
export { count, add };

引用使用import from

如果定义时使用export default来暴露属性的时候,可以使用import from来给引入的属性起别名
如果定义时是使用export 那必须严格按照定义时的名称来引入

import { count, add } from './mymodule';
console.log(add(count,1))

还有一点值得关注的是
ES6是引用是 对象指针引用
CommonJS的引用 是模块的拷贝引用