Webpack实战:入门、进阶与调优
上QQ阅读APP看书,第一时间看更新

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语句放在模块的末尾。