前言

想开始编写Node.js代码,那么我们就必须先熟悉它的模块化规范CommonJS,本文将详细讲解CommonJS规范

本文代码 >>> github 地址

CommonJS

Node 应用由模块组成,采用 CommonJS 模块规范。

每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。

【特点】

  • 所有代码都运行在模块作用域,不会污染全局作用域。
  • 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
  • 模块加载的顺序,按照其在代码中出现的顺序。

新建文件example.js

  1. // example.js
  2. var x = 5;
  3. var addX = function (value) {
  4. return value + x;
  5. };

上面代码中,变量x和函数addX,是当前文件example.js私有的,其他文件不可见。

如果想在多个文件分享变量,必须定义为global对象的属性。

  1. global.warning = true;

上面代码的warning变量,可以被所有文件读取。当然,这样写法是不推荐的。

module.exports

CommonJS规范规定,每个模块内部,module变量代表当前模块。

这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。

加载某个模块,其实是加载该模块的module.exports属性。

新建文件02_module.js

  1. console.log('module');
  2. const NUM = 100;
  3. function test (){
  4. console.log(NUM);
  5. }
  6. // 输出常量
  7. module.exports.num = NUM;
  8. // 输出函数
  9. module.exports.testFn = test;

exports 与 module.exports

它们之间是一层引用关系,exports 引用了 module.exports对象

06_exports.js

  1. console.log(exports,module.exports); // {} , {}
  2. exports.num = '100';
  3. console.log(exports,module.exports); // { num: '100' } { num: '100' }

看上面的代码的输出可以证明exports 引用了 module.exports。那么之前我们采用module.exports输出的内容,其实可以简写为exports输出

【错误的做法】

  1. exports = {
  2. a:1,
  3. b:2
  4. };

上面代码会切断 exports 对 module.exports的引用关系。导致输出的文件,在其它文件是无法使用的

[注意]建议还是使用module.exports规范些,不会产生额外的错误!

require

require方法用于加载模块。

新建文件 03_require.js

  1. const m1 = require('./02_module');
  2. m1.testFn();

执行命令:

  1. node 03_require.js

运行结果:

【路径】

[1] / 表示绝对路径,./ 表示相对于当前文件的路径,

[2] 不写路径则认为是 build-in模块或者各级 node_modules内的第三方模块

  1. const m1 = require('./02_module.js'); // 这样就会在同级目录中寻找02_module.js文件
  2. const m = require('02_module.js'); // 这样只会去 node_modules去寻找相应的文件

【加载文件】

[1]支持js、json、node 拓展名,不写依次尝试加载

  1. const m1 = require('./02_module'); // 这样会在同级目录中寻找 是否有02_module.js 的文件如果有则加载,如果没有则去寻找是否有02_module.json 或者 02_module.node 文件

【特性】

[1]module 被加载的时候执行,加载后缓存

创建文件 04_catch.js

  1. >>> 当我们连续两次引入同一个文件其实只会执行一次
  2. const m1 = require('./02_module');
  3. const m2 = require('./02_module');
  4. // 同时引入两次 02_module文件

我们执行命令 :node 04_catch.js,输出结果:

[2]一旦出现某个模块被循环加载,就只输出已执行的部分,还未执行的部分不会输出

  1. // 1、创建文件:05_modA.js
  2. module.exports.test = 'A';
  3. const modB = require('./05_modB');
  4. console.log('modA: ', modB.test);
  5. module.exports.test = 'AA';
  6. // 2、创建文件:05_modB.js
  7. module.exports.test = 'B';
  8. const modA = require('./05_modA');
  9. console.log('modB: ', modA.test);
  10. module.exports.test = 'BB';
  11. // 3、创建文件:05_main.js
  12. const modA = require('./05_modA');
  13. const modB = require('./05_modB');

我们可以看到 modA中引入modB,modB中也引入了modA,它们形成了循环引用。那么此时执行 node 05_main.js 会输出什么呢?

其实就是遵循上诉原理:一旦出现某个模块被循环加载,就只输出已执行的部分,还未执行的部分不会输出。大家可以动起手来敲敲代码很好理解的。

[注意]平时写代码的时候切记要避免循环引用

Node.js实战项目学习系列(3) CommonJS 模块化规范的更多相关文章

  1. Node.js实战项目学习系列(1) 初识Node.js

    前言 一直想好好学习node.js都是半途而废的状态,这次沉下心来,想好好的学习下node.js.打算写一个系列的文章大概10几篇文章,会一直以实际案例作为贯穿的学习. 什么是node Node.js ...

  2. Node.js实战项目学习系列(2) 开发环境和调试工具

    前言 上一节让我们对Node.js有一个初步的了解,那么现在可以开始正式学习下Node.js的开发了,但是任何一门语言要设计到开发,就必须先学习开发环境以及调试.本文将主要讲解这些内容. 本文涉及到的 ...

  3. Node.js实战项目学习系列(4) node 对象(global、process进程、debug调试)

    前言 在之前的课程我们学习了Node的模块化规则,接下来我们将学习下 Node的几个新特性:global ,process进程,debug调试 global 跟在浏览器中的window一样都是全局变量 ...

  4. Node.js实战项目学习系列(5) node基础模块 path

    前言 前面已经学习了很多跟Node相关的知识,譬如开发环境.CommonJs,那么从现在开始要正式学习node的基本模块了,开始node编程之旅了. path path 模块提供用于处理文件路径和目录 ...

  5. iKcamp团队制作|基于Koa2搭建Node.js实战项目教学(含视频)☞ 环境准备

    安装搭建项目的开发环境 视频地址:https://www.cctalk.com/v/15114357764004 文章 Koa 起手 - 环境准备 由于 koa2 已经开始使用 async/await ...

  6. 前端(Node.js)(3)-- Node.js实战项目开发:“技术问答”

    1.Web 与 Node.js 相关技术介绍 1.1.Web应用的基本组件 web应用的三大部分 brower(GUI)<==>webserver(business logic.data ...

  7. 开始连载啦~每周2更共11堂iKcamp课|基于Koa2搭建Node.js实战项目教学(含视频)| 课程大纲介绍

  8. Node.js 实战 & 最佳 Express 项目架构

    Node.js 实战 & 最佳 Express 项目架构 Express Koa refs https://github.com/xgqfrms/learn-node.js-by-practi ...

  9. 《Node.js实战(双色)》作者之一——吴中骅访谈录

随机推荐

  1. LivePhoto开发,你要知道的知识点

    前言 Apple从iPhone6s开始支持Live Photo.Live Photo 会录下拍照前后 1.5 秒所发生的一切,因此用户获得的不仅仅是一张精美照片,还有拍照前后时刻的动作和声音.具体的操 ...

  2. git 忽略 .idea文件

    多人开发时,会出现明明在gitignore中忽略了.idea文件夹,但是提交时仍旧会出现.idea内文件变动的情况 原因.idea已经被git跟踪,之后再加入.gitignore后是没有作用的 解决办 ...

  3. 解决java compiler level does not match the version of the installed java project facet【转载】

    原博文地址http://blog.csdn.net/chszs/article/details/8125828 Java compiler level does not match the versi ...

  4. Golang 入门系列(七) Redis的使用

    安装 1. Redis 的安装很简单,我这里测试直接用的是windows 的版本.如何安装就不细说了.想了解的可以看之前的文章:https://www.cnblogs.com/zhangweizhon ...

  5. iOS开发基础-UIScrollView实现图片缩放

    当用户在 UIScrollView 上使用捏合手势时, UIScrollView 会给 UIScrollViewDelegate 协议发送一条消息,并调用代理的 viewForZoomingInScr ...

  6. 【原创】分布式之大话CAP

    引言 本文翻译自博客 http://ksat.me/a-plain-english-introduction-to-cap-theorem/ 博主觉得这个故事讲的生动活泼,因此翻译来给大家分享,顺便加 ...

  7. 云计算openstack共享组件(3)——消息队列rabbitmq

    队列(MQ)概念: MQ 全称为 Message Queue, 消息队列( MQ ) 是一种应用程序对应用程序的通信方法.应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链 ...

  8. 如何给框架添加API接口日志

    前言 用的公司的框架,是MVC框架,看了下里面的日志基类,是操作日志,对增删改进行记录, 夸张的是一张业务的数据表 需要一张专门的日志表进行记录, 就是说你写个更新,添加的方法都必须写一遍操作日志,代 ...

  9. 数据库主键到底是用自增长(INT)好还是UUID好

    其实针对使用自增长还是UUID,大家讨论最多的就是速度和存储空间,这里我加入了安全性和分布式,具体对比如下: 使用自增长做主键的优点:1.很小的数据存储空间2.性能最好3.容易记忆使用自增长做主键的缺 ...

  10. Android——图片轮播

    Android技术——轮播功能 轮播需要什么? 答:实现图片与广告语展示.循环播发以及手动切换.支持加载本地与网络图片. 性能优化? 答:多张图片与指示器展示.自动与定时.循环播发.滑动流畅并且无卡顿 ...