Nodejs module.exports与exports??关于exports的总结

Nodejs module.exports与exports??关于exports的总结

API文档是枯燥的,下面本人收集了一些论坛经常有人疑问和开源代码中经常遇到的案例供大家研究一下。

文章博客地址 排版更佳。。

##module.exports与exports的区别

每一个node.js执行文件,都自动创建一个module对象,同时,module对象会创建一个叫exports的属性,初始化的值是 {}

 module.exports = {};

Node.js为了方便地导出功能函数,node.js会自动地实现以下这个语句

foo.js

 exports.a = function(){
 console.log('a')
 }

exports.a = 1

test.js

 var x = require('./foo');

 console.log(x.a)

看到这里,相信大家都看到答案了,exports是引用 module.exports的值。module.exports 被改变的时候,exports不会被改变,而模块导出的时候,真正导出的执行是module.exports,而不是exports

再看看下面例子

foo.js

 exports.a = function(){
  console.log('a')
 }

module.exports = {a: 2} exports.a = 1

test.js

 var x = require('./foo');

 console.log(x.a)

result:

 2

exports在module.exports 被改变后,失效。

是不是开始有点廓然开朗,下面将会列出开源模块中,经常看到的几个使用方式。

##module.exports = View

function View(name, options) { 
   options = options || {};
   this.name = name;
   this.root = options.root;
   var engines = options.engines;
   this.defaultEngine = options.defaultEngine;
   var ext = this.ext = extname(name);
   if (!ext && !this.defaultEngine) throw new Error('No default engine was specified and no         extension was provided.');
   if (!ext) name += (ext = this.ext = ('.' != this.defaultEngine[0] ? '.' : '') +     this.defaultEngine);
   this.engine = engines[ext] || (engines[ext] = require(ext.slice(1)).__express);
   this.path = this.lookup(name);
 }

module.exports = View;

javascript里面有一句话,函数即对象,View 是对象,module.export =View, 即相当于导出整个view对象。外面模块调用它的时候,能够调用View的所有方法。不过需要注意,只有是View的静态方法的时候,才能够被调用,prototype创建的方法,则属于View的私有方法。

foo.js

 function View(){

}

View.prototype.test = function(){ console.log(‘test’) }

View.test1 = function(){ console.log(‘test1’) }

module.exports = View

test.js

 var x = require('./foo');

console.log(x) //{ [Function: View] test1: [Function] } console.log(x.test) //undefined console.log(x.test1) //[Function] x.test1() //test1

##var app = exports = module.exports = {};

其实,当我们了解到原理后,不难明白这样的写法有点冗余,其实是为了保证,模块的初始化环境是干净的。同时也方便我们,即使改变了 module.exports 指向的对象后,依然能沿用 exports的特性

 exports = module.exports = createApplication;

/**

  • Expose mime. */

exports.mime = connect.mime;

例子,当中module.exports = createApplication改变了module.exports了,让exports失效,通过exports = module.exports的方法,让其恢复原来的特点。

##exports.init= function(){}

这种最简单,直接就是导出模块 init的方法。

##var mongoose = module.exports = exports = new Mongoose;

集多功能一身,不过根据上文所描述的,大家应该不能得出答案。


12 回复

Nodejs module.exportsexports总结

模块导出机制

在Node.js中,每个执行文件都会自动创建一个module对象,该对象有一个名为exports的属性,默认值为 {}module.exportsexports都是用来导出模块的功能,但它们之间存在一些关键的区别。

module.exportsexports的区别

  1. 初始化

    module.exports = {};
    
  2. exports引用module.exports

    exports.a = function() {
        console.log('a');
    };
    

    例如,在foo.js中:

    exports.a = function() {
        console.log('a');
    };
    
    exports.a = 1;
    

    test.js中:

    var x = require('./foo');
    
    console.log(x.a);  // 输出: 1
    

    这里可以看到exports只是引用了module.exports的值。当module.exports被改变时,exports不会被改变,但是模块导出的是module.exports,而不是exports

  3. module.exports被改变后exports失效

    exports.a = function() {
        console.log('a');
    };
    
    module.exports = { a: 2 };
    exports.a = 1;
    

    test.js中:

    var x = require('./foo');
    
    console.log(x.a);  // 输出: 2
    

    module.exports被改变后,exports中的设置将不再有效。

module.exports导出对象

function View(name, options) {
    options = options || {};
    this.name = name;
    this.root = options.root;
    var engines = options.engines;
    this.defaultEngine = options.defaultEngine;
    var ext = this.ext = extname(name);
    if (!ext && !this.defaultEngine) throw new Error('No default engine was specified and no extension was provided.');
    if (!ext) name += (ext = this.ext = ('.' != this.defaultEngine[0] ? '.' : '') + this.defaultEngine);
    this.engine = engines[ext] || (engines[ext] = require(ext.slice(1)).__express);
    this.path = this.lookup(name);
}

module.exports = View;

在这个例子中,module.exports直接指向了View构造函数。这意味着外部可以访问并使用View的所有公共方法。

保持模块初始化环境的干净

var app = exports = module.exports = {};

/**
 * Expose mime.
 */
exports.mime = connect.mime;

这种写法是为了确保模块的初始化环境是干净的,并且即使改变了module.exports,仍然可以利用exports的特性。

直接导出方法

exports.init = function() {
    console.log('init method');
};

这种是最简单的导出方式,直接导出一个方法。

集多功能于一体的导出

var mongoose = module.exports = exports = new Mongoose;

这种方式将多种功能集成到一起,尽管看起来复杂,但遵循上述原则,我们可以理解其工作原理。

通过这些示例和解释,希望你能更好地理解和使用Node.js中的module.exportsexports


上 Wiki?

明白了。

通俗易懂,好理解,深入浅出

一般我们这里是这样写的: function view(){}; function view2(){}; module.exports = { view: view, view2: view2 } 你们写法是否不同。。。。。

自己模拟实现exports和module.exports导出功能,原理同Node的实现原理一致

  • 创建一个foo.js文件,内容如下:
exports.foo = 'bar';
创建index.js文件,内容如下:
  • // 1. 在Node中,每个文件模块都是一个对象,我们模拟一个
function Module() {
  this.exports = {};
}
  • // 2. Node在定位到具体的文件后,Node会新建一个模块对象
var module = new Module();
  • // 3. 如果是.js文件。Node会通过fs模块同步读取文件
var fs = require('fs');
var foo_js = fs.readFileSync('./foo.js');
  • // 4. 读取出文件内容后,将文件进行头尾包装,这里只是简单的模拟
var packStr = '(function(exports,module){' + foo_js + ' return module.exports; })';

// 注:这样每个模块之间都进行了作用域隔离

  • // 5. 包装之后的代码通过一个类似eval(Node中并不是eval)的函数执行返回一个具体的function对象
var packObj = eval(packStr);
  • // 6. 执行该函数,将module对象的exports属性以及module对象本身作为参数传递进去
  • // 而内部是通过return module.exports; 的方式返回的
var foo = packObj(module.exports, module);

// 在第6点中,就是为什么通过exports = ‘bar’; 赋值,但是外部却拿不到 // 这是因为在JavaScript中,引用传递的是引用的副本,而不是引用本身,这叫做共享传递 // 所以exports = ‘bar’ 改变的是形参的引用()而并没有影响到外部的实参exports对象 // 而通过exports.foo = ‘bar’; 确实可以得到,这是因为虽然引用传递的是引用副本,但他们指向的是同一个对象 // 自然而然的,通过module.exports = ‘bar’; 就是成功的

// 7. 所以在外部我们最终得到了被引用模块中导出的变量、函数或对象

console.log(foo);

文章博客地址 这个地址是什么鬼 吓我一跳

哈哈,链接好评

Node.js module.exportsexports

在Node.js中,module.exportsexports 都用于导出模块中的内容。但它们之间的关系和行为有所不同。

区别

  1. module.exports

    • 这是Node.js内部用来指定模块导出内容的对象。
    • 当你直接赋值给 module.exports 时,会覆盖当前的导出内容。
  2. exports

    • exports 是对 module.exports 的引用。
    • 如果你直接修改 exports,实际上是修改了 module.exports 的属性。
    • 但是当 module.exports 被重新赋值时,exports 将不再有效。

示例代码

// foo.js
function View() {
    console.log('View instance created');
}

View.prototype.test = function() {
    console.log('test');
};

View.test1 = function() {
    console.log('test1');
};

module.exports = View;

// test.js
const x = require('./foo');

console.log(x); // { [Function: View] test1: [Function] }
x.test1(); // 输出: 'test1'
// x.test(); // undefined,因为原型链上的方法未被导出

在这个例子中:

  • module.exports = View; 导出了 View 构造函数。
  • test1View 的静态方法,可以通过实例化后的对象调用。
  • test 方法在原型链上,但由于 module.exports 只导出了构造函数本身,所以无法通过 x.test() 访问到。

其他常见用法

  1. var app = exports = module.exports = {};
// app.js
var app = exports = module.exports = {};

app.init = function() {
    console.log('App initialized');
};

// main.js
const app = require('./app');
app.init(); // 输出: 'App initialized'

在这个例子中,exports 初始指向 module.exports,然后被重新赋值为 {},以确保 module.exports 指向新的对象。这样可以在后续操作中继续使用 exports

  1. exports.init = function() {}
// bar.js
exports.init = function() {
    console.log('Initialization complete');
};

// main.js
const bar = require('./bar');
bar.init(); // 输出: 'Initialization complete'

在这个例子中,init 方法直接添加到了 exports 上,因此可以通过 require 导入并调用。

通过这些示例,你可以更好地理解 module.exportsexports 在Node.js中的作用及区别。

回到顶部