Structure-study-Node(process、CommonJS)

312 阅读3分钟

global

浏览器的全局对象是window,而Node的全局对象是global。在Node中可以直接访问global,默认声明的属性时不放在global上的,因为Node的每个模块最外层包了一个匿名函数,也就是说this === module.exports

global 中的属性叫全局属性 + module,exports require __dirname __filename 叫全局对象(在文件内部也是可以直接使用)

    // 这样可以获取global上的内容
    (function(){
        console.log(Object.keys(this))
    })()

process

  • process.argv

代表用户通过node执行文件传递的参数 默认前两个参数 没有实际意义

    // node index.js --port = 3000 --config = 'xxx'
    console.log(process.argv.slice(2))

    // 取到传递参数的方法
    
    let config = process.argv.slice(2).reduce((memo,current,index,array)=>{
        if(current.includes('--')){
            memo[current.slice(2)] = array[index+1];
        }
        return memo;
    },{});

可以配合commander 来解析process.argv 并且生成类似cli的命令帮助等。

    const program = require('commander');
    const chalk = require('chalk');
    // 解析用户的参数 默认提供--help
    program // 配置命令 我输入命令后 要执行一些内容
        .command('create')
        .alias('c')
        .description('create project')
        .action(()=>{
            console.log('create project')
        })
    program //配置属性 给代码传递参数
        .option('-p, --port <val>','set port')
        .version('1.0.0')
    program.on('--help',()=>{
        console.log('\r\nExamples')
        console.log('  node 1.js --help');
        console.log('  node 1.js create '+chalk.green('project'))
    }).parse(process.argv);
    // chalk 粉笔
    console.log(program.port);
  • process.chdir

方法变更 Node.js 进程的当前工作目录,如果变更目录失败会抛出异常

  • process.cwd()

返回 Node.js 进程的当前工作目录。在哪里执行这个文件 ,目录就是哪里 代表的就是执行的文件的目录

  • process.nextTick(Node中的微任务)

定义出一个动作,并且让这个动作在下一个事件轮询的时间点上执行

  • process.env

环境变量,可以根据这个变量的不同执行不同的结果,window和mac设置这个变量的方式不同,可以使用cross-env来统一设置。

CommonJS规范及实现

实现步骤

  • req方法传递文件路径,Module.resolveFileName解析为绝对路径
  • 判断缓存,存在直接使用,不存在创建新的模块,然后加入缓存
  • 模块加载module.load,返回module.exports
    • 根据不同的文件后缀名,采取不同的方法
    • json文件直接返回,js文件使用闭包包裹,然后使用vm.runInThisContext生成函数执行
    const path = require("path");
    const fs = require("fs");
    const vm = require("vm");
    function Module(id) {
    this.id = id;
    this.exports = {}; // 模块的结果
    }
    Module.wrapper = [
    "(function(module,exports,require,__filename,__dirname){",
    "})"
    ];
    Module.extensions = {
    ".js"(module) {
        let script = fs.readFileSync(module.id, "utf8");
        let fnStr = Module.wrapper[0] + script + Module.wrapper[1];
        let fn = vm.runInThisContext(fnStr); // 让字符串变成js代码
        // 第一个参数是改变this指向  module  module.exports
        fn.call(
        module.exports,
        module,
        module.exports,
        req,
        module.id,
        path.dirname(module.id)
        );
        // exports 已经让用户更改了
    }, // js需要将exports 传入给用户 用户自己赋值
    ".json"(module) {
        // 解析后 node默认会赋值
        let script = fs.readFileSync(module.id, "utf8");
        module.exports = JSON.parse(script);
    }
    };
    // 给你一个相对路径 解析成绝对路径
    Module.resolveFileName = function(filename) {
    // 1) 把相对路径转化成绝对路口 默认会先判断一下是否是绝对路径
    let absPath = path.resolve(__dirname, filename);
    let flag = fs.existsSync(absPath); // 判断文件是否存在 异步方法被废弃
    let current = absPath; // 默认是当前路径
    if (!flag) {
        let keys = Object.keys(Module.extensions);
        for (let i = 0; i < keys.length; i++) {
        current = absPath + keys[i]; // 当前找到的文件路径
        let flag = fs.existsSync(current);
        if (flag) {
            break;
        } else {
            current = null;
        }
        }
    }
    if (!current) {
        // 如果没有 说明加了后缀文件还是不存在
        throw new Error("文件不存在");
    }
    return current; // 返回文件的路径
    };
    Module.prototype.load = function() {
    // 模块加载就是读取文件的内容
    let ext = path.extname(this.id);
    Module.extensions[ext](this); // 根据不同的后缀 调用不同的处理方法
    };
    Module.cache = {};
    function req(filename) {
    // 自己实现了一个require方法
    let current = Module.resolveFileName(filename);
    if (Module.cache[current]) {
        return Module.cache[current].exports;
    }
    let module = new Module(current); // 产生一个module
    Module.cache[current] = module;
    module.load();

    return module.exports; // 默认导出module.exports对象
    }