nodejs中exports和module.exports的区别

用一句话来说明就是,require方能看到的只有module.exports这个对象,它是看不到exports对象的,而我们在编写模块时用到的exports对象实际上只是对module.exports的引用

如果你能理解上面这句话,那么下面的都是废话,可以不用看了,因为是用来解释上面这句话的。

关于引用,可以用下面的例子来让你搞得请清楚楚的:

首先说一个概念:

ECMAScript的变量值类型共有两种:

基本类型 (primitive values) : 包括Undefined, Null, Boolean, Number和String五种基本数据类型;

引用类型 (reference values) : 保存在内存中的对象们,不能直接操作,只能通过保存在变量中的地址引用对其进行操作。

我们今天要讨论的exports和module.exports属于Object类型,属于引用类型。

看下面的例子:

var module = {
    exports:{
        name:"我是module的exports属性"
    }
};
var exports = module.exports;  //exports是对module.exports的引用,也就是exports现在指向的内存地址和module.exports指向的内存地址是一样的

console.log(module.exports);    //  { name: '我是module的exports属性' }
console.log(exports);   //  { name: '我是module的exports属性' }


exports.name = "我想改一下名字";


console.log(module.exports);    //  { name: '我想改一下名字' }
console.log(exports);   //  { name: '我想改一下名字' }
//看到没,引用就是a和b都操作同一内存地址下的数据


//这个时候我在某个文件定义了一个想导出的模块
var Circle = {
    name:"我是一个圆",
    func:function(x){
        return x*x*3.14;
    }
};

exports = Circle;  //   看清楚了,Circle这个Object在内存中指向了新的地址,所以exports也指向了这个新的地址,和原来的地址没有半毛钱关系了

console.log(module.exports);    //  { name: '我想改一下名字' }
console.log(exports);   // { name: '我是一个圆', func: [Function] }

回到nodejs中,module.exports初始的时候置为{},exports也指向这个空对象。

那么,这样写是没问题的:

exports.name = function(x){
    console.log(x);
};

//和下面这个一毛一样,因为都是修改的同一内存地址里的东西


module.exports.name = function(x){
    console.log(x);
};

但是这样写就有了区别了:

exports = function(x){
    console.log(x);
};

//上面的 function是一块新的内存地址,导致exports与module.exports不存在任何关系,而require方能看到的只有module.exports这个对象,看不到exports对象,所以这样写是导不出去的。

//下面的写法是可以导出去的。说句题外话,module.exports除了导出对象,函数,还可以导出所有的类型,比如字符串、数值等。
module.exports = function(x){
    console.log(x);
};

我讲清楚了吧?