2.1.2 导出
导出是一个模块向外暴露自身的唯一方式。在CommonJS中,通过module.exports可以导出模块中的内容,如:
module.exports = { name: 'calculater', add: function(a, b) { return a + b; } };
CommonJS模块内部会有一个module对象用于存放当前模块的信息,可以理解成在每个模块的最开始定义了以下对象:
var module = {...}; // 模块自身逻辑 module.exports = {...};
module.exports用来指定该模块要对外暴露哪些内容,在上面的代码中我们导出了一个对象,包含name和add两个属性。为了书写方便,CommonJS也支持另一种简化的导出方式—直接使用exports。
exports.name = 'calculater'; exports.add = function(a, b) { return a + b; };
在实现效果上,这段代码和上面的module.exports没有任何不同。其内在机制是将exports指向了module.exports,而module.exports在初始化时是一个空对象。我们可以简单地理解为,CommonJS在每个模块的首部默认添加了以下代码:
var module = { exports: {}, }; var exports = module.exports;
因此,为exports.add赋值相当于在module.exports对象上添加了一个属性。
在使用exports时要注意一个问题,即不要直接给exports赋值,否则会导致其失效。如:
exports = { name: 'calculater' };
上面代码中,由于对exports进行了赋值操作,使其指向了新的对象,module.exports却仍然是原来的空对象,因此name属性并不会被导出。
另一个在导出时容易犯的错误是不恰当地把module.exports与exports混用。
exports.add = function(a, b) { return a + b; }; module.exports = { name: 'calculater' };
上面的代码先通过exports导出了add属性,然后将module.exports重新赋值为另外一个对象。这会导致原本拥有add属性的对象丢失了,最后导出的只有name。
另外,要注意导出语句不代表模块的末尾,在module.exports或exports后面的代码依旧会照常执行。比如下面的console会在控制台上打出“end”:
module.exports = { name: 'calculater' }; console.log('end');
在实际使用中,为了提高可读性,不建议采取上面的写法,而是应该将module.exports及exports语句放在模块的末尾。