commonJS

属性描述的问题

  1. //有什么区别?
  2. var a = 1; configurable false; 不可删除不可配置
  3. window.b; configurable true; writable true

问题:require是什么?

它不属于全局对象提供的方法,它源于commonJS规范

问题:commonJS模块是什么?

后端模块化规范

问题:为什么区分前后端规范?

前端以前没有规范,随着业务复杂才有,前后端干活不一样,一个同步加载,一个异步加载

问题:后端commonJS规范有什么用?

  1. (function(exports require, module, __filename, __dirname){})();
  1. //arguments在前端会报错,后端是一个arguments对象
  2. arguments{
  3. 0: {}, //this
  4. 1: '...', //require(fn)
  5. 2: '...', //module
  6. 3: '...', //__filename 绝对路径
  7. 4: '...' //__dirname
  8. }
  9. console.log(this === module.exports); //true
  10. console.log(this === exports); //true
  11. console.log(exports === module.exports); //true 说明两者指针相同,指向同一对象
  12. //module.exports = {} exports = {}
  13. console.log(argument[0] === this); //true
  14. console.log(argument[0] === module.exports); //true
  15. console.log(argument[1] === require); //true
  16. console.log(argument[2] === module); //true
  17. console.log(argument[3] === __filename); //true
  18. console.log(argument[4] === __dirname); //true
  19. //写法1:
  20. module.exports = { a: 1 }
  21. //写法2:
  22. exports.a = 1;
  1. //重写require实现模块加载
  2. function myRequire(filename){
  3. //相对目录变成绝对目录
  4. const current = resolveFilename(filename);
  5. //判断是否存在模块
  6. if(Module._cache[current]){
  7. return Module._cache[current].exports;
  8. }
  9. //根据路径实例化一个模块
  10. let module = new Module(current);
  11. //缓存加载
  12. Module._cache[current] = module;
  13. //加载模块
  14. module.load();
  15. //返回对象
  16. return module.export;
  17. }
  18. function Module(filename){
  19. //每个模块有自己的id
  20. this.id = filename;
  21. //默认为空对象
  22. this.exports = {};
  23. }
  24. //相对目录变成绝对目录
  25. Module.resolveFilename = function(filename){
  26. //PS:
  27. //current work directorly - 当前工作目录
  28. //__filename 绝对路径
  29. //process.cwd() 当前路径
  30. //path.resolve() 将多个路径片段拼接成为绝对路径
  31. //当前路径 + 当前文件名
  32. const absPath = path.resolve(__dirname, filename);
  33. console.log(absPath);
  34. //c:\users\desktop\a
  35. let current = absPath;
  36. //判断文件是否存在
  37. let flag = fs.existsSync(absPath);
  38. if(!flag){
  39. //路径不存在,没有找到路径,需要加后缀
  40. //['.js', '.json'] => ['c:\users\desktop\a.js', 'c:\users\desktop\a.json']
  41. Object.keys(Module.extensions)
  42. .map(key => current + key)
  43. .filter(current => fs.existsSync(current))
  44. .join();
  45. //如果current为空
  46. if(!current){
  47. throw new Error('文件不存在');
  48. }
  49. }
  50. }
  51. //根据不同文件类型采取不同的方式
  52. Module.prototype.load = function(){
  53. //获取当前路径的拓展名
  54. let ext = path.extname(this.id);
  55. //console.log(ext);
  56. //.js
  57. //读取JS or 读取JSON 调用后缀对应的方法 传入当前模块
  58. Module.extensions[ext](this);
  59. }
  60. //调用对应模块后缀对应的方法
  61. Module.extensions = {
  62. '.js'(module){
  63. //读取JS文件
  64. let script = fs.readFileSync(module.id, 'utf-8');
  65. //用函数的方式把JS文件里的字符串包裹
  66. //node的API 可以替代eval方法
  67. //vm.runInThisContext(Module.wrapper[0] + script + Module.wrapper[1]);
  68. let fn = eval(Module.wrapper[0] + script + Module.wrapper[1]);
  69. //exports require, module, __filename, __dirname
  70. fn.call(
  71. module.exports,
  72. module.exports,
  73. myRequire,
  74. module,
  75. module.id,
  76. path.dirname(module.id)
  77. );
  78. //挂载当前模块的export上
  79. module.exports = JSON.parse(json);
  80. },
  81. '.json'(module){
  82. //读取JSON文件
  83. let json = fs.readFileSync(module.id, 'utf-8');
  84. console.log(json);
  85. //["xx":"xx", "xxx":"xxx"]
  86. //挂载当前模块的export上
  87. module.exports = JSON.parse(json);
  88. }:
  89. }
  90. //包装函数
  91. Module.wrapper = [
  92. '';(function(){',
  93. '})()'
  94. ]
  95. //缓存模块
  96. Module._cache = {}
  97. myRequire('./a');

补充:策略模式是什么?