走过路过发现 bug 请指出,拯救一个辣鸡(但很帅)的少年就靠您啦!!!
1. 为什么需要 Javascipt 模块化?
1.解决命名冲突。将所有变量都挂载在到全局 global
会引用命名冲突的问题。模块化可以把变量封装在模块内部。
2.解决依赖管理。Javascipt 文件如果存在相互依赖的情况就需要保证被依赖的文件先被加载。使用模块化则无需考虑文件加载顺序。
3.按需加载。如果引用 Javascipt 文件较多,同时加载会花费加多时间。使用模块化可以在文件被依赖的时候被加载,而不是进入页面统一加载。
4.代码封装。将相同功能代码封装起来方便后续维护和复用。
2. 你知道哪几种模块化规范?
CommonJS
Node.js 采用了 CommonJS 模块规范。
CommonJS 规范规定,每个模块内部,module
变量代表当前模块。这个变量是一个对象,它的 exports
属性(即 module.exports
)是对外的接口。加载某个模块,其实是加载该模块的 module.exports
属性。使用 require
方法加载模块。模块加载的顺序,按照其在代码中出现的顺序。
模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
引入模块得到的值其实是模块输出值的拷贝,如果是复杂对象则为浅拷贝。
// a.js
let count = 1;
function inc() {count++;
}
module.exports = {count: count,inc: inc
};
// b.js
const a = require('./a.js');
console.log(a.count); // 1
a.inc();
console.log(a.count); // 1
因为 CommonJS 输出的是值的浅拷贝,也就是说 count
在输出后就不再和原模块的 count
有关联。
在 Node 中每一个模块都是一个对象,其有一个 exports
属性,就是文件中指定的 module.exports
,当我们通过 require
获取模块时,得到的就是 exports
属性。再看另一个例子:
// a.js
module.exports = 123;
setTimeout(() => {module.exports = 456;
}, 1000);
// b.js
console.log(require('./a.js')); // 123
setTimeout(() => {console.log(require('./a.js')); // 456
}, 2000);
模块的 module.exports
值改变了,我们通过 require
获取模块的值也会发生变化。
CommonJS 使用了同步加载,即加载完成后才进行后面的操作,所以比较适合服务端,如果用在浏览器则可能导致页面假死。
AMD
AMD(Asynchronous Module Definition,异步加载模块定义)。这里异步指的是不堵塞浏览器其他任务(dom构建,css渲染等),而加载内部是同步的(加载完模块后立即执行回调)。 AMD 也采用 require
命令加载模块,但是不同于 CommonJS,它要求两个参数,依赖模块和回调:
require([module], callback);
以 RequireJS 示例, 具体语法可以参考 requirejs.org/