妙啊!简单理解Node中模块化(module)的实现原理。(module.exports和require的原理)

什么是模块化?️

在使用Node写代码的时候,我们常常会使用module.exports来导出一个变量或函数,用require(文件名)来导入对应的变量或函数

示范:

在Node上写代码的小伙伴都知道:

先来看这段代码(hello.js)

var str = '你好';
function hello(name) {
	console.log(str+','+name+'!');
};
module.exports = hello;

如果在一个js里这么写,可以利用module.exports = hello;来将hello()这个函数进行“导出”到某个地方。

然后在另一个js文件中:(main.js)

var hello =require('./hello.js');
var str = 'Hello';
hello('苏一恒');//你好,苏一恒!

通过require(文件名)来获取到被导出到hello()函数并加以调用。

此时控制台输出“你好,苏一恒!”

思考?

当我们写让浏览器加载的JavaScript时,不是通过<script>引入一堆外部js吗,那样就相当于将所有的js文件混杂到一个文件中,所有的变量都共享:

问题1:为啥str没有被覆盖?

问题2:module.exports=hello;是如何将hello暴露出去的?

问题3:require('./hello.js');是如何获取到被暴露出的hello()函数的?

解答?

问题1:为啥str没有被覆盖?

这里其实用到了闭包的原理。什么是闭包?如果你不知道,你可以先简单理解成“定义在一个函数内部的函数”,目的是读取函数内部的变量,将变量保存在内存中。

其实Node对你写的js文件进行了一个包裹:

(function () {
   //你的js代码
})();

这样你的文件就变成了一个匿名内部函数,其他文件也是匿名内部函数,而函数内部的变量互不干扰,所以str就没有被覆盖了。

(function(){})()这种表达还是一种“立即执行函数(IIFE)”的语法。

问题2:module.exports=hello;是如何将hello暴露出去的?

这里其实是Node在处理你的js文件的时候,对里面的代码进行了巧妙的封装:

// 定义一个module
var module = {
    id: 'hello',
    exports: {}
};
var load = function (module) {

    // 读取的hello.js代码:
    var str = '你好';
    function hello(name) {
    	console.log(str+','+name+'!');
    };
    module.exports = hello;
    // hello.js代码结束

    return module.exports;
};
var exported = load(module);
// 保存module,只用知道被Node保存了就行
save(module, exported);

为了讲解方便,我将hello.js代码前的代码记作A,将hello,js代码记作B,将hello.js代码后的代码记作C,

所以B代码是被夹在了A和C之间。

这一夹,Node完全按照js的正常逻辑把hello()函数保存在了某个地方,这样就能在其他地方获取到hello了,从而实现了"导出"(向外暴露)的效果。其实,Node只是单纯地进行了代码合并,巧妙的将“module.exports”这种看起来“语义化”的代码,当作一个赋值语句添加在AC模版中间。这里不得不佩服创造这种逻辑的人,点赞?!

问题3:require('./hello.js');是如何获取到被暴露出的hello()函数的?

由于Node保存了所有的module,当require()时就能将对应当module里面当exports返回,这样在另一个模块中就顺利拿到了被暴露的东西。

总结

存在即合理。

js由于太“松散自由”,被吐槽了那么多年,祸兮,福之所倚;福兮,祸之所伏。凡事各有利弊,你看这个好的特性被挖掘出来,就很容易进入潮流了,谁知道未来还有没有更新的模式被挖掘呢?自由度高,创造了条件。

个人觉得,未来js还是可以大方光彩的,作为一个前端,由衷地开心。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`import` 和 `export` 是现代 JavaScript(ES6 及以上版本)模块引入和导出机制,而 `require` 和 `module.exports` 是 Node.js 传统的模块加载方式。两者的主要区别在于: 1. **作用域和模块上下文**: - `import` 语句使得你可以在模块内部导入其他模块的代码块,创建一个封闭的作用域。这样,你可以避免全局污染,并且导入的内容只在当前模块的范围内可见。 - `require` 需要在 Node.js 运行,它在全局作用域下查找并加载模块,这可能导致无意的变量共享。 2. **语法和用法**: - `import` 支持静态导入,意味着编译时可以确定导入内容,提高了性能,同时还可以使用解构赋值等更灵活的导入方式。 - `module.exports` 用于导出一个模块的内容,它通常是一个对象,当你使用 `require` 时会返回整个导出对象。 3. **动态导入**: - `import()` 是动态导入,支持在运行时决定要加载的模块,这对于异步加载大文件或模块树非常有用。 - `require()` 没有内置的动态导入功能,需要借助第三方库(如 `dynamic-import-node`)实现。 4. **模块系统不同**: - ES6 的模块系统是 CommonJS 的超集,Node.js 原生支持 CommonJS。 - ES6 的模块系统更现代,推崇更简洁、面向对象的编程风格。 因此,`import` 和 `export` 提供了更符合现代 JavaScript 规范、易于理解和维护的模块编程方式,特别是在开发 Web 应用程序时,它们是标准的写法。而在 Node.js ,尽管 `import` 和 `export` 也可以被模拟使用,但建议使用 `require` 和 `module.exports` 或者 `export default` 的组合,以保持向后兼容。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值