Commonjs规范

为什么有模块化

  • 1.方便代码维护
  • 2.每个功能放到一个模块内
  • 3.解决命名问题,全局变量污染问题

常见的模块化

  • 1.我们写方法写属性都放在对象里(单例模式)
    • 缺陷声明的对象也有可能命名冲突,不能完全解决上述问题
var obj = {
    a:1,
    init(){
        
    }
    fn(){
        
    }
}
复制代码
  • 2.自执行函数(IIFE) 实现模块化的功能,要把最终的结果对外暴露
    • 好处
      • 1.没有名字
      • 2.有自己单独的执行作用域
      • 3.可以对外暴露一些属性
    • 缺陷
      • 浏览器的文件加载(http请求),异步的问题不易解决
(function(){
    ...;
    return XXX
})()
复制代码

commonjs规范定义了几个点(同步的)

  • 1.如何声明一个模块,node中一个文件就是一个模块
  • 2.每个模块都需要导出最终的结果module.exports
  • 3.每个模块使用其他模块的时候需要使用require方法

commonjs的实现流程

就是把文件读取出来之后加一个 函数 执行 最终返回的是module.exports

  • 1.每个模块都有一个require方法-->Module.prototype.require
  • 2.调用Module._load()加载模块
  • 3.调用Module._resolveFilename()解析出文件的绝对路径,并且增加拓展名
  • 4.通过Module._cache[filename]检查是否存在缓存,如果有直接返回缓存模块的module.exports
  • 5.检查是否是内置模块(例如fs模块),如果不是,通过new Module(filename)创建一个模块,模块上有两个重要的属性id&&exports = {}
  • 6.将创建的模块放到缓存中Module._cache[filenama] = module
  • 7.尝试加载模块tryModuleLoad(module, filename)核心
    • 1).通过path.extname(filename)获取文件的扩展名extension
    • 2).通过扩展名extensionModule._extensions中找相应的方法读取文件content
    • 3).通过Module.wrap(content)方法将读取到的内容进行包装,返回包装后的结果wrapper
    • 4).通过vm.runInThisContext(wrapper)返回一个可执行函数compiledWrapper
    • 5).compiledWrapper.call(this.exports, this.exports, require, this, filename, dirname)执行
let path = require('path');
let fs = require('fs');
let vm = require('vm');

function req(pathname) {
  return Module._load(pathname);
}

function tryModuleLoad(module, filename) {
  return module.load(filename);
}

function Module(id) {
  this.id = id;
  this.exports = {};
}

Module.prototype.load = function (filename) {
  let extension = path.extname(filename);
  Module._extensions[extension](this);
  return this.exports;
}

Module._extensions = {
  '.js': function (module) {
    let content = fs.readFileSync(module.id, 'utf8');
    let wrapper = Module.wrap(content);
    let compiledWrapper = vm.runInThisContext(wrapper);
    let result = compiledWrapper.call(module.exports, module.exports, req, module)
    Module._cache[module.id] = result;
  },
  '.json': function (module) {
    let result = JSON.parse(fs.readFileSync(module.id, 'utf8'));
    Module._cache[module.id] = result;
    module.exports = result;
  }
}

Module._cache = {};

Module._load = function (pathname) {
  let filename = Module._resolveFilename(pathname);
  let cacheModule = Module._cache[filename];
  if (cacheModule) return cacheModule.exports;
  /* 此处略掉检查内部模块 */
  let module = new Module(filename);
  return tryModuleLoad(module, filename);
}

Module._resolveFilename = function (pathname) {
  let absName = path.resolve(__dirname, pathname);
  try {
    fs.accessSync(absName);
  } catch (err) {
    let extArr = ['.js', '.json'];
    let ext = path.extname(absName);
    if (!ext || !extArr.includes(ext)) {
      extArr.every((extname, index) => {
        let spliceName = absName + extname;
        try {
          fs.accessSync(spliceName);
          absName = spliceName;
          return false;
        } catch (err) {
          if (index == 1) {
            throw new Error(`${pathname} is not defined`)
          }
          return true
        }
      })
    } else {
      throw new Error(`${pathname} is not defined`)
    }
  }
  return absName
}

Module.wrap = function (content) {
  return Module.wrapper[0] + content + Module.wrapper[1];
}

Module.wrapper = ['(function (exports, require, module, __filename, __dirname) {', '});']

let r = req('./user');
console.log(r);

复制代码

转载于:https://juejin.im/post/5c6ba879e51d45704055fbce

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值