JS module输出原理

module输出写法

为了能够复用一些基本功能,我们通常会将其封装在module中。类似这样子:

1
2
3
4
5
6
7
8
9
10
//greet.js
'use strict';
var s = 'Hello';
function greet(name) {
console.log(s + ', ' + name + '!');
}
module.exports = greet;

我们也会看到其他的写法,这样的:

1
2
3
'use strict';
exports.foo = 'foo';

直接通过exports的属性来输出的,这样看起来其实很迷惑人,比如我第一次就有疑惑:

  • module不是模块的意思吗? 为什么要使用module.exports的赋值来输出?
  • 为什么有时候是exports来赋值输出
  • 其他的地方,是如何使用我的模块呢?
  • 为什么export有些可以输出多个值呢? 比如: modelu.exports = {foo: foo, tool: tool}

原理

这里其实是module在默默地做了一些事情,它会在代码中植入类似这样的代码:

1
2
3
4
5
6
7
8
var module = {
id: 'greet',
exports: {},
}
exports = moduel.exports;
load(module.exports, module);

这样,我们就知道了为什么exportsmodule.exports都可以作为模块的输出。

这里还要一个要注意的,之所以可以用exports来输出,是因为它指向了module.exports. 所以当exports的指针被修改的时候,这样用就会出问题了。

如果输出是一个数组,或者函数,则两者是不等价的,看下面的例子:

例子一: 等价的输出

1
2
3
module.exports = {foo: 'foo'};
exports.foo = 'foo';

例子而: 不等价输出

1
2
3
4
5
6
module.exports = function greet(){console.log('greet')};//这时 module.exports指向greet函数
exports = function greet(){console.log('greet')};//这时,exoprts的指针指向greet函数,而module.exports仍然指向{}
这里两种方式不等价,主要是因为原来都指向同一个变量,而如果赋值是数据,函数等,则export会改变指针的值。然后最终输出的还是module.exports, 所以在这里,模块的输出就不可以用export

廖雪峰的博客说是建议全部使用module.exports,这样可以避免混淆。我的建议是大家最好搞清楚原理,这样使用起来才知其所以然。

ok,总结这篇文章,主要是讲了模块(module)的输出原理,为什么有两种写法,为什么每种写法都可以work,两种写法的区别和使用时机。

引用