CJS规范

2019/11/30 javascript

前端模块化——CJS规范

1、模块化

常用的模块化规范有:ES6模块化,CJS模块化,不常用的有AMD,CMD.

ES6模块化:ES6的模块化分为导出(export)与导入(import)两个模块, export 可以有多个,export default 仅有一个。

  export let myName="laowang";
  import {myName} from "./test.js";
  console.log(myName);//laowang

CJS模块化规范:每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。Node 应用由模块组成,采用 CommonJS 模块规范。分为导出(module.exports)与导入(require)两个模块。

  • PS: 由于node每个文件都被认为是一个模块,所以每个文件里面的this,指的是module.exports,而不是global

2、模块化特点

  1. 防止命名冲突
  2. 作用域问题

3、实现原理

因为node可以读取文件,所以node实现了CJS规范。然后使用node的path、fs、vm模块进行查找文件,读取文件,然后使用vm模块把字符串外层套了一层匿名自执行函数,返回一个module.exports

先创建一个文件a.js, 里面输入module.exports = 'hello';。 创建一个cjs.js,开始写一个简易版的cjs原理。

  const fs = require('fs');
  const path = require('path');
  const vm = require('vm');
  function myReq(filePath){
    // 拿到绝对路径
    let absolutePath = path.resolve(__dirname, filePath);
    // 拿到文件后需要创建一个模块,每一个模块都需要有一个exports属性
    let module = new Module(absolutePath);
    // 创建完模块加载模块的数据
    module.load();
    return module.exports;
  }

  // 创建模块
  function Module(path){
    this.path = path;
    this.exports = {};
  }

  Module.prototype.load = function() {
    // 读取到文件内部的代码
    let jsStr = fs.readFileSync(this.path, 'utf8');
    // 包裹一层函数
    let fnStr = `(function(exports, module, require){
      ${jsStr}
    })`;
    // 转换成函数
    let fn = vm.runInThisContext(fnStr);
    fn.call(this.exports, this.exports, this, myReq);
  }

  let h = myReq('./a.js');
  console.log(h);

如果是json文件的话直接JSON.parse解析成对象,赋值为module.exports

3.1 vm模块

vm提供了一个沙箱环境(即安全环境,函数内部执行不会去查找外部的变量,只能在内部调用运行)。

执行字符串函数不能使用new Function or eval,是因为他们会调用外部作用域的同名变量的,容易引发错误。

Search

    Table of Contents