简介及资料

通过Node.js的官方API可以看到Node.js本身提供了很多核心模块 http://nodejs.org/api/ ,这些核心模块被编译成二进制文件,可以require('模块名')去获取;核心模块具有最高的加载优先级(有模块与核心模块同名时会体现)

(本次主要说自定义模块)

Node.js还有一类模块为文件模块,可以是JavaScript代码文件(.js作为文件后缀)、也可以是JSON格式文本文件(.json作为文件后缀)、还可以是编辑过的C/C++文件(.node作为文件后缀);

文件模块访问方式通过require('/文件名.后缀')    require('./文件名.后缀')    requrie('../文件名.后缀') 去访问,文件后缀可以省略;以"/"开头是以绝对路径去加载,以"./"开头和以"../"开头表示以相对路径加载,而以"./"开头表示同级目录下文件,

前面提到文件后缀可以省略,Nodejs尝试加载的优先级 js文件 > json文件 > node文件

创建一个自定义模块

  以一个计数器为例

var outputVal  = 0;     //输出值
var increment = 1; //增量 /* 设置输出值 */
function seOutputVal (val) {
outputVal = val;
} /* 设置增量 */
function setIncrement(incrementVal){
increment = incrementVal;
} /* 输出 */
function printNextCount()
{
outputVal += increment;
console.log(outputVal) ;
} function printOutputVal() {
console.log(outputVal);
}
exports.seOutputVal = seOutputVal;
exports.setIncrement = setIncrement; module.exports.printNextCount = printNextCount;
    示例中重点在于exports和module.exports;提供了外部访问的接口,下面调用一下看看效果吧

调用自定义模块

/*
一个Node.js文件就是一个模块,这个文件可能是Javascript代码、JSON或者编译过的C/C++扩展。
重要的两个对象:
require是从外部获取模块
exports是把模块接口公开
*/
var counter = require('./1_modules_custom_counter'); console.log('第一次调用模块[1_modules_custom_counter]'); counter.seOutputVal(10); //设置从10开始计数
counter.setIncrement (10); //设置增量为10 counter.printNextCount();
counter.printNextCount();
counter.printNextCount();
counter.printNextCount(); /*
require多次调用同一模块不会重复加载
*/
var counter = require('./1_modules_custom_counter'); console.log('第二次调用模块[1_modules_custom_counter]');
counter.printNextCount();

  运行可以发现通过exports和module.exports对外公开的方法都可以访问!

  示例中可以看到,我两次通过require('./1_modules_custom_counter')获取模块,但是第二次引用后调用printNextCount()方法确从60开始~~~

  原因是node.js通过requirerequire多次调用同一模块不会重复加载,Node.js会根据文件名缓存所有加载过的文件模块,所以不会重新加载了

  注意:通过文件名缓存是指实际文件名,并不会因为传入的路径形式不一样而认会是不同的文件

  在我创建的1_modules_custom_counter文件中有一个printOutputVal()方法,它并没有通过exports或module.exports提供对外公开访问方法,

  如果1_modules_load文件中直接访问运行会出现什么样的情况呢?

  答案是:TypeError: Object #<Object> has no method 'printOutputVal'

exports和module.exports 区别

经过上面的例子,通过exports和module.exports对外公开的方法都可以访问!那既然两种都能达到效果,但总得有点区别的吧~~~用个例子看看吧!

var counter  = 0;     

exports.printNextCount = function (){
counter += 2;
console.log(counter);
} var isEq = (exports === module.exports); console.log(isEq);

下面再新建个2_modules_diff_exports_load.js文件调用一下

var Counter = require('./2_modules_diff_exports');

Counter.printNextCount();

  调用后,执行结果如上图

  我在2_modules_diff_exports_load.js文件中输出了isEq的值  ( var isEq = (exports === module.exports); ),返回的true

  PS:注意是三个等号,如果不清楚自已查查资料吧!

  不用急着下结论,把这两个JS文件分别改成module.exports对应的代码

//修改后的2_modules_diff_exports.js源码如下
var counter = 0; module.exports = function(){
counter += 10;
this.printNextCount = function()
{
console.log(counter);
}
} var isEq = (exports === module.exports); console.log(isEq);
//修改后的2_modules_diff_exports_load.js文件源码如下
var Counter = require('./2_modules_diff_exports'); var counterObj = new Counter();
counterObj.printNextCount();

  调用后,执行结果如上图

  我在2_modules_diff_exports_load.js文件中输出了isEq的值  ( var isEq = (exports === module.exports); ),返回的false,这与用先前得到的结果不一致!

  PS:不要用Counter.printNextCount();去访问,你只会得到一个错误的提示

API提供了解释

  http://nodejs.org/api/modules.html

  Note that exports is a reference to module.exports making it suitable for augmentation only. If you are exporting a single item such as a constructor you will want to use module.exports directly instead
exports仅仅是module.exports的一个地址引用。nodejs只会导出module.exports的指向,如果exports指向变了,那就仅仅是exports不在指向module.exports,于是不会再被导出

参考其它理解:

  http://www.hacksparrow.com/node-js-exports-vs-module-exports.html
  http://zihua.li/2012/03/use-module-exports-or-exports-in-node/
  module.exports才是真正的接口,exports只不过是它的一个辅助工具。 最终返回给调用的是module.exports而不是exports。 
  所有的exports收集到的属性和方法,都赋值给了Module.exports。当然,这有个前提,就是module.exports本身不具备任何属性和方法。
  如果,module.exports已经具备一些属性和方法,那么exports收集来的信息将被忽略。

exports和module.exports 覆盖

  上面也也基本明白了exports和module.exports的关系和区别,但如果同时针对printNextCount()方法存在exports和module.exports,结果如何?

  调用结果

  从结果可以看出,并没有报错,表示可以这么定义,但最终module.exports覆盖了exports

  虽然结果不会报错,如果这么用开发中难免会有一些问题存在,所以

1.最好别分别定义module.exports和exports

2.NodeJs开发者建议导出对象用module.exports,导出多个方法和变量用exports

其它...

API中还提供了其它的方法,就不细讲了,在上面例子的基础上自已动手一输出就知道了

  module.id

  返回string类型的模块标识,一般为完全解析后的文件名

  module.filename

  返回一个string类型的完全解析后文件名

  module.loaded

  返回一个bool类型,表示是否加载完成

  module.parent

  返回引用该模块的模块

  module.children

  返回该模块引用的所有模块对象的数组

此系列的源代码可到http://bijian1013.iteye.com/blog/2425085下载。

文章来源:https://www.cnblogs.com/zhongweiv/p/nodejs_module.html

Nodejs学习笔记(三)—模块的更多相关文章

  1. nodejs学习笔记<三>关于路由(url)

    在网站开发中,路由的设置非常关键.nodejs对路由处理封装了一个比较全面的模块. 来认识下url模块 1)在命令行(cmd)可以直接 node —> url 可直接查看url模块的所有方法. ...

  2. nodejs学习笔记三——nodejs使用富文本插件ueditor

    在做自己的nodejs项目的时候遇到需要使用ueditor.原来下载的是ueditor的jsp版本.目录如下  在ueditor.config.js中有配置服务器home路径(这个home路径能找到u ...

  3. NodeJS学习笔记三

    map map对象是一个简单的键/值映射.任何值(包括对象和原始值)都可以用作一个键或一个值. var m = new Map(); var o = {p: "Hello World&quo ...

  4. nodejs学习笔记三(用户注册、登录)

    1.定接口      /user 接口               输入    act=reg&user=aaa&pass=123456               输出     {& ...

  5. NodeJS学习笔记 (23)模块机制-module

    https://github.com/chyingp/nodejs-learning-guide

  6. NodeJS学习笔记 进阶 (12)Nodejs进阶:crypto模块之理论篇

    个人总结:读完这篇文章需要30分钟,这篇文章讲解了使用Node处理加密算法的基础. 摘选自网络 Nodejs进阶:crypto模块之理论篇 一. 文章概述 互联网时代,网络上的数据量每天都在以惊人的速 ...

  7. Nodejs学习笔记(三)——一张图看懂Nodejs建站

    前言:一条线,竖着放,如果做不到精进至深,那就旋转90°,至少也图个幅度宽广. 通俗解释上面的胡言乱语:还没学会爬,就学起走了?! 继上篇<Nodejs学习笔记(二)——Eclipse中运行调试 ...

  8. NodeJS学习笔记之Connect中间件模块(一)

    NodeJS学习笔记之Connect中间件模块(一) http://www.jb51.net/article/60430.htm NodeJS学习笔记之Connect中间件模块(二) http://w ...

  9. [Firefly引擎][学习笔记三][已完结]所需模块封装

    原地址:http://www.9miao.com/question-15-54671.html 学习笔记一传送门学习笔记二传送门 学习笔记三导读:        笔记三主要就是各个模块的封装了,这里贴 ...

  10. Nodejs学习笔记(四)——支持Mongodb

    前言:回顾前面零零碎碎写的三篇挂着Nodejs学习笔记的文章,着实有点名不副实,当然,这篇可能还是要继续走着离主线越走越远的路子,从简短的介绍什么是Nodejs,到如何寻找一个可以调试的Nodejs ...

随机推荐

  1. 使用Xcode 7 beta免费真机调试iOS应用程序

    使用Xcode 7 beta免费真机调试iOS应用程序 六月 9, 2015  |   K-Res 发布   今天凌晨的WWDC15虽然没有熬夜守候吧,但也还是早起第一时间翻看了twitter的相关标 ...

  2. Gitlab搭建安装及使用中遇到的问题。

    一.CentOS7安装gitlab-ce 1.下载及安装rpm软件包. 下载RPM包 curl -LJO https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/ ...

  3. TFS Training for Kunlun bank (http://www.klb.cn/) 微软研发流程(ALM)管理培训会议(昆仑银行) 2016.09.21

    银行一直是微软技术的伤心地,由于历史原因,微软技术和产品一直很难进入到银行业务的核心区域,但是微软今年来的进步不少,在开发工具和平台方面已经连续攻克了几个典型的金融企业,例如农业银行,中国人保等. 应 ...

  4. kylin的clube合并后清理hbase中产生的相关历史表

    kylin的clube合并后清理hbase中产生的相关历史表 kylin 的clube 历史的每次构建,都会产生一个hbase的表:虽然可以设置按照一定策略合并,但是合并后hbase 历史表不会被自动 ...

  5. asp.net—单例模式

    一.单例模式是什么? 定义:确保一个类仅仅能产生一个实例,并且提供一个全局访问点来获取该实例. 二.单例模式怎么用? class SingleCase { public string Name{get ...

  6. Windows10 家庭版添加【本地组策略编辑器】

    Windows10 家庭版默认没有[本地组策略编辑器],添加方法: 新建记事本复制以下内容 @echo off pushd "%~dp0" dir /b C:\Windows\se ...

  7. CefSharp禁止弹出新窗体,在同一窗口打开链接,并且支持带type="POST" target="_blank"的链接

    1.实现ILifeSpanHandler接口,代码如下: using CefSharp; using CefSharp.WinForms; using System; using System.Col ...

  8. JavaScript模块化与esl.js

    2016-2-2 晚上 松合时代公寓中 1.前端为什么需要模块化? http://requirejs.org/docs/why.html 2.https://github.com/ecomfe/esl ...

  9. S11 day 96 RestFramework 之认证权限

    一.设计一个简易的登录 1. 建立一个模型 class UserInfo(models.Model): username =models.CharField(max_length=) password ...

  10. xgboost 和GBDT的区别

    作者:wepon链接:https://www.zhihu.com/question/41354392/answer/98658997来源:知乎 传统GBDT以CART作为基分类器,xgboost还支持 ...