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