commonJs之require原理

113 阅读2分钟

require是什么

require是nodejs提供的一种CommonJS规范的模块化引入api。每个.js文件都是一个模块,它们内部各自使用的变量名和函数名都互不冲突。一个模块提供module.exports对外暴露变量,使用require('id')引入其他模块输出的对象

模块化原理

因js语言作用域分为全局作用域与局部作用域,定义全局作用域的变量所有地方都可访问但变量名不可重复,局部作用域变量仅作用域块内可用。受自身作用域限制,没有一种机制可实现不同模块可使用相同的变量名,变量独立且互不影响。为了解决上述问题,Nodejs实现module编程使用闭包的思想,这样变量就成了函数的局部变量,从而实现了模块隔离。

示例: hello.js文件如下

var s = 'Hello';  
var name = 'world';  
console.log(s + ' ' + name + '!');  

Node.js加载了hello.js后,它可以把代码包装一下,变成这样执行:

(function () {
    // 读取的hello.js代码:
    var s = 'Hello';
    var name = 'world';

    console.log(s + ' ' + name + '!');
    // hello.js代码结束
})();

这样一来,原来的全局变量s现在变成了匿名函数内部的局部变量。如果Node.js继续加载其他模块,这些模块中定义的“全局”变量s也互不干扰。这就是Nodejs模块隔离思想。

模块的输出module.exports怎么实现?

// 先准备module对象:
var module = {
    id: 'hello',
    exports: {}
};
// 传入加载函数
var load = function (module) {
    // 读取的hello.js代码:
    function greet(name) {
        console.log('Hello, ' + name + '!');
    }
    
    module.exports = greet;
    // hello.js代码结束
    return module.exports;
};
var exported = load(module);
// 保存module:
save(module, exported);

由于Node保存了所有导入的module,当我们用require()获取module时,Node找到对应的module,把这个moduleexports变量返回,这样,另一个模块就顺利拿到了模块的输出

写法

如果要输出一个键值对象{},可以利用exports这个已存在的空对象{},并继续在上面添加新的键值;

如果要输出一个函数或数组,必须直接对module.exports对象赋值。

所以我们可以得出结论:直接对module.exports赋值,可以应对任何情况:

module.exports = {
    foo: function () { return 'foo'; }
};

或者:

module.exports = function () { return 'foo'; };

最终,我们强烈建议使用module.exports = xxx的方式来输出模块变量,这样,你只需要记忆一种方法。