前文讲到在Angular Material的第二个编译文件 docs/gulpfile.js
中却看到了一个奇怪的东西 module.exports
那么 module.exports
是什么东西呢?
一直以来,javascript最大的诟病就是全局变量,这也成为大型应用开发的最大阻碍。因此,很多人使用了很多方式来解决这个问题。如模块模式(Module Pattern), 而node.js这实现了模块装载系统,来解决组件实现的基本问题。
自从开始研究前端,我也几个相关的关键词在眼前晃荡, require()
exports
等等。当时,因为注意力在其他方面,一直也没下决心研究清楚。 就如下面 文章 中所讲:
作为开发人员常常面临这样的困境:当我们使用不熟悉的代码(库)时,我们究竟要花多少时间来研究它的原理和实现,这个研究又要有多深呢?经典答案就是,学习到足够可以开始写代码就可以了,等到时间容许在进一步深入研究。
那么现在就是深入研究 module.exports
的时候了!
这里是一个简单的js文件, greeting.js
,它的功能一看就明白:
//greetings.js sayHelloInEnglish = function() { return "Hello"; }; sayHelloInSpanish = function() { return "Hola"; }; 这里有两函数也就是两个功能。
// var exports = module.exports ={};
exports.sayHelloInEnglish = function() { return "Hello"; }; exports.sayHelloInSpanish = function() { return "Hola"; };
module.exports = { sayHelloInEnglish = function() { return "Hello"; }; sayHelloInSpanish = function() { return "Hola"; }; };
这个方式看上去有点怪异,之后可以做更进一步的解释。在这之前,可以透露一点小道消息。 Typescript定义模块的语法就感觉自然多了:
module namespace { exports function sayHelloInEnglish = function() { return "Hello"; };
而用tsc转译以后,他就会变成上面的node.js语法。什么是Typescript? OK,以后有时间再深入吧? (听起来怎么这么耳熟?)
我们准备在main.js中导入和使用greetings.js中的所有函数。
require
是nodejs用来导入模块的关键词。想象一下require的定义如下 (怎么又是想象?)
var require =function(path){ //.... return module.exports; };
//main.js var greetings = require("./greetings");
想象一下以上代码等价于你的代码做了以下事情:
//main.js var greetings = { sayHelloInEnglish = function() { return "Hello"; }; sayHelloInSpanish = function() { return "Hola"; }; };
//"Hello" greetings.sayHelloInEnglish(); // "Hola" greetings.sayHelloInSpanish();
警告:
正因为nodejs的这种模块机制,如果不小心给module.exports重新赋给了一个全新的对象,会导致不可预期的问题。
如:
//greetings.js //var exports=module.exports = {}; exports.sayHelloInEnglish = ... exports.sayHelloInSpanish = ... /* 重新赋值module.exports */ module.exports= "Bonjour";
这时候,在main.js中我们在调用`greetings.sayHelloInEnglish()'就会出错。