目录
模块化规范:一个模块=实现特定功能的一组方法。
全局污染:共享时,同名变量冲突
依赖管理:下层 js 能调用上层 js 的方法,但是上层 js 无法调用下层 js 的方法
- // 模块A
- var ModuleA = {
- func1: function() {
- // ...
- },
- func2: function() {
- // ...
- }
- };
-
- // 模块B
- var ModuleB = {
- func3: function() {
- // ...
- }
- };
后面提出了对象,通过将函数作为一个对象的方法来实现,但是这种办法会暴露所 有的所有的模块成员,外部代码可以修改内部属性的值。
现在最常用的是立即执行函数的写法,通过利用闭包来实现模块私有作用域的建立,同时不会对全局作用域造成污染。
- //IIFE(立即调用函数表达式)
- //创建一个私有作用域,避免变量之间的冲突。然后,通过返回一个对象或函数来暴露模块的公共部分
- // 模块A
- var ModuleA = (function() {
- var privateVar = "private";
-
- function privateFunc() {
- // ...
- }
-
- return {
- publicVar: "public",
- publicFunc: function() {
- // ...
- }
- };
- })();
module:在 commonjs
中每一个 js 文件都是一个单独的模块
module 上保存了 exports 等信息之外,还有一个 loaded(bool)
表示该模块是否被加载。
Module
:以 nodejs 为例,整个系统运行之后,会用 Module
缓存每一个module的信息。
- //home.js
- const sayName = require('./hello.js')
- module.exports = function say(){
- return {
- name:sayName(),
- }
- }
- //编译进行首尾包装
- (function(exports,require,module,__filename,__dirname){
- const sayName = require('./hello.js')
- module.exports = function say(){
- return {
- name:sayName(),
- }
- }
- })
- //包装函数
- function wrapper (script) {
- return '(function (exports, require, module, __filename, __dirname) {' +
- script +
- '\n})'
- }
- //runInThisContext
- eavl(包装后的module)(module.exports, require, module, __filename, __dirname)
- //a.js
- const getMes = require('./b')
- console.log('我是 a 文件')
- exports.say = function(){
- const message = getMes()
- console.log(message)
- }
- //b.js
- const getMes = require('./a')
- console.log('我是 b 文件')
- exports.say = function(){
- const message = getMes()
- console.log(message)
- }
- //main.js
- const a = require('./a')
- const b = require('./b')
-
- console.log('node 入口文件')
- const say = require('./a')
- console.log('我是 b 文件')
- console.log('打印 a 模块' , say)
-
- setTimeout(()=>{
- console.log('异步打印 a 模块' , say)
- },0)
-
- exports.say = function(){
- const message = getMes()
- console.log(message)
- }
加载之后的文件的 module
会被缓存到 Module
上,比如一个模块已经 require 引入了 a 模块,如果另外一个模块再次引用 a ,那么会直接读取缓存值 module ,所以a中的代码只会执行一次
require 本质上就是一个函数,那么函数可以在任意上下文中执行,来自由地加载其他模块的属性方法。
当 module.exports
导出的是一个对象时,对象的引用关系是被保留的,这意味着其他模块引入这个对象后,即使该对象后续被修改,其他模块也能看到这些修改。这是因为对象在 JavaScript 中是引用类型,它们的引用关系是保持的。
- exports.author = '7'
- exports.say = function (){
- console.log(666)
- }
- module.exports ={
- author:'7',
- say(){
- console.log(666)
- }
- }
在循环引用的时候,就容易造成属性丢失的情况发生
- module.exports = a // 导出变量
-
- module.exports = [1,2,3] // 导出数组
-
- module.exports = function(){} //导出方法
在服务器端,同步加载模块的方式是可行的,因为模块通常都在本地。
ES模块的结构在编译时就确定下来,模块的依赖关系在代码运行前就已经确定。静态导入导出:方便 tree shaking