关于javascript:node中的exportsmoduleexportsthis

4次阅读

共计 2502 个字符,预计需要花费 7 分钟才能阅读完成。

node 源码

const path = require("path");
const fs = require("fs");
const vm = require("vm");

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

Module.wrap = function (script) {
  let arr = ["(function (exports, require, module, __filename, __dirname){",
    script,
    "})",
  ];
  return arr.join("");
};

Module._extensions = {".js": function (module) {let content = fs.readFileSync(module.id, "utf8");
    let fnStr = Module.wrap(content);
    let fn = vm.runInThisContext(fnStr);
    let exports = module.exports;
    let require = myRequire;
    let __filename = module.id;
    let __dirname = path.dirname(module.id);
    // 这里的 this   就是 exports 对象
    fn.call(exports,exports, require, module, __filename, __dirname);
    // 用户会给 exports 赋值
    // console.log(fn.toString());
  },
  ".json": function (module) {let content = fs.readFileSync(module.id);
    module.exports = JSON.parse(content);
  },
};

Module._resolveFilename = function (filepath) {let filePath = path.resolve(__dirname, filepath);
  let exists = fs.existsSync(filePath);
  if (exists) return filePath;

  // 尝试增加后缀
  let keys = Object.keys(Module._extensions);
  for (let i = 0; i < keys.length; i++) {let curentPath = filePath + keys[i];
    if (fs.existsSync(curentPath)) {return curentPath;}
  }
};

Module.prototype.load = function (filename) {
  // 获取文件的后缀进行加载
  let extname = path.extname(filename);
  Module._extensions[extname](this); // 依据对应的后缀名进行加载
};

Module._load = function (filepath) {
  // 将门路转化成绝对路径
  let filename = Module._resolveFilename(filepath);
  let module = new Module(filename);
  module.load(filename);

  return module.exports;
};

function myRequire(filepath) {
  // 依据门路加载这个模块
  return Module._load(filepath);
}

exports/module.exports/this 的关系

fn.call(exports,exports, require, module, __filename, __dirname);
从代码中咱们能够看到 this 就是 exports。
a.js 文件代码

console.log(this === exports); // true
console.log(this === module.exports); // true
console.log(module.exports === exports); // true

module.exports = 1;

use.js 文件

let r = require("./a");  // 同步语法
console.log(r);

从下面的代码咱们能够确认
this === exports === module.exports

exports 和 module.exports 输入后果为什么不一样

既然 this === exports === module.exports,为什么在 a.js 文件中上面的代码获取后果不一样呢?

exports = 1; // 如果应用 exports = 1, 获取的时候失去的是值是 {}
module.exports = 1; // 获取的值是 1 

看上面代码,思考为什么这样

  let a = b = {}
  a = 1;
  console.log(b); // 输入后果是 {},而不是 1 
  let a = b = {}
  a = 'hello';
  console.log(b);// 输入后果是 {},而不是 1 
  let a = b = {}
  a = {name:'fung', age:3};
  console.log(b); // 输入后果是 {},而不是 1 
let a = b = {}
a.name = 'a';
a.age = 3;
console.log(b); // 输入后果是 {name: 'a', age: 3},而不是 {}

下面三个代码例子就能够阐明为什么 exports 和 module.exports 输入后果不一样。
开始的时候

let exports = module.exports = {}
fn.call(exports,exports, require, module, __filename, __dirname);
return module.exports

开始 exports module.exports this 都指向同一个援用地址,当咱们给 exports 赋值的时候,则断开了 exports 的指向,并不会扭转 module.exports 和 this 的指向问题。
然而上面代码的输入后果则是一样的

 module.exports.a = 1 // 输入 {a: 1}
 exports.a = 1 // 输入 {a: 1}
 this.a = 1  // 输入 {a: 1}
正文完
 0