在开发一个复杂的应用程序的时候,我们需要把各个功能拆分、封装到不同的文件,在需要的时候引用该文件。没人会写一个几万行代码的文件,这样在可读性、复用性和维护性上都很差,几乎所有的编程语言都有自己的模块组织方式,比如Java中的包、C#中的程序集等,node.js使用模块和包来组织,其机制实现参照了CommonJS标准,虽未完全遵守,但差距不大,使用起来非常简单。

什么是模块

在node.js中模块与文件是一一对应的,也就是说一个node.js文件就是一个模块,文件内容可能是我们封装好的一些JavaScript方法、JSON数据、编译过的C/C++拓展等,在关于node.js的误会提到过node.js的架构

其中http、fs、net等都是node.js提供的核心模块,使用C/C++实现,外部用JavaScript封装。

创建、加载模块

模块在node.js中的概念很简单,看看如何创建一个我们自己的模块供开发复用。

在node.js中创建模块非常简单,一个文件就是一个模块,所以我们创建一个test.js文件就创建了一个模块

test.js

var name='';

function setName(n){
name=n;
} function printName(){
console.log(name);
}

问题是怎么使外部访问这个module,我们知道客户端的JavaScript使用script标签引入JavaScript文件就可以访问其内容了,但这样带了的弊端很多,最大的就是作用域相同,产生冲突问题,以至于前端大师们想出了立即执行函数等方式,利用闭包解决。node.js使用exports和require对象来解决对外提供接口和引用模块的问题。

我们可以把模块中希望被外界访问的内容定义到exports对象中,对test.js稍作修改就可以了

test.js

var name='';

function setName(n){
name=n;
} function printName(){
console.log(name);
} exports.setName=setName;
exports.printName=printName;

这样我们在相同路径下创建index.js,使用require引用一下test.js module

index.js

var test=require('./test');

test.setName('Byron');
test.printName();

exports一个对象

有时候我们希望模块对外提供的使一个对象,修改一下test.js

test.js

var Student=function(){
var name=''; this.setName=function(n){
name=n;
}; this.printName=function(){
console.log(name) ;
};
}; exports.Student=Student;

这样我们对外提供了一个Student类,在使用的时候需要这样

var Student=require('./test').Student;
var student=new Student();
student.setName('Byron');
student.printName();

require('./test').Student 很丑陋的样子,我们可以简单修改一下exports方式,使require优雅一些

test.js

var Student=function(){
var name=''; this.setName=function(n){
name=n;
}; this.printName=function(){
console.log(name) ;
};
}; module.exports=Student;

这样我们的require语句就可以优雅一些了

var Student=require('./test');

很神奇的样子,不是说好的exports是模块公开的接口嘛,那么module.exports是什么东西?

module.exports与exports

事实的情况是酱紫的,其实module.exports才是模块公开的接口,每个模块都会自动创建一个module对象,对象有一个modules的属性,初始值是个空对象{},module的公开接口就是这个属性——module.exports。既然如此那和exports对象有毛线关系啊!为什么我们也可以通过exports对象来公开接口呢?

为了方便,模块中会有一个exports对象,和module.exports指向同一个变量,所以我们修改exports对象的时候也会修改module.exports对象,这样我们就明白网上盛传的module.exports对象不为空的时候exports对象就自动忽略是怎么回事儿了,因为module.exports通过赋值方式已经和exports对象指向的变量不同了,exports对象怎么改和module.exports对象没关系了。

大概就是这么过程

module.exports=exports={};
...... module.exports=new Object(); exports=xxx;//和new Object没有关系了,最后返回module.exports,所以改动都无效了

一次加载

无论调用多少次require,对于同一模块node.js只会加载一次,引用多次获取的仍是相同的实例,看个例子

test.js

var name='';

function setName(n){
name=n;
} function printName(){
console.log(name);
} exports.setName=setName;
exports.printName=printName;

index.js

var test1=require('./test'),
test2=require('./test'); test1.setName('Byron');
test2.printName();

执行结果并不是'',而是输出了test1设置的名字,虽然引用两次,但是获取的是一个实例

require搜索module方式

node.js中模块有两种类型:核心模块和文件模块,核心模块直接使用名称获取,比如最长用的http模块

var http=require('http');

在上面例子中我们使用了相对路径 './test'来获取自定义文件模块,那么node.js有几种搜索加载模块方式呢?

  1. 核心模块优先级最高,直接使用名字加载,在有命名冲突的时候首先加载核心模块
  2. 文件模块只能按照路径加载(可以省略默认的.js拓展名,不是的话需要显示声明书写)

    1. 绝对路径
    2. 相对路径
  3. 查找node_modules目录,我们知道在调用 npm install <name> 命令的时候会在当前目录下创建node_module目录(如果不存在) 安装模块,当 require 遇到一个既不是核心模块,又不是以路径形式表示的模块名称时,会试图 在当前目录下的 node_modules 目录中来查找是不是有这样一个模块。如果没有找到,则会 在当前目录的上一层中的 node_modules 目录中继续查找,反复执行这一过程,直到遇到根 目录为止。

node.js module初步理解-(转载)的更多相关文章

  1. node.js module初步理解

    在开发一个复杂的应用程序的时候,我们需要把各个功能拆分.封装到不同的文件,在需要的时候引用该文件.没人会写一个几万行代码的文件,这样在可读性.复用性和维护性上都很差,几乎所有的编程语言都有自己的模块组 ...

  2. Node.js 的初步理解

    Node.js 是一个采用C++语言编写的后端的 Javascript 的运行环境, 它使用了 google 的 V8虚拟机来解释和执行代码.Node.js 的有许多有用的内置的模块,比如 http, ...

  3. 如何發佈一個完整Node.js Module

    本文會透過以下幾個段落,讓各位一步一步學習如何寫一個自已的Node.js Module並且發佈到npm package上 Node.js Module 結構 我們先建立一個 NodeModuleDem ...

  4. (转)Node.js module.exports与exports

    本文转自Node.js module.exports与exports 作者: chemdemo 折腾Node.js有些日子了,下面将陆陆续续记录下使用Node.js的一些细节. 熟悉Node.js的童 ...

  5. 创建并发布node.js module

      创建node.js module. 创建一个文件夹,用来存放module. Cd到新创建的文件夹,运行npm init,会提示输入package的信息. 可以按照这个视频的来输入.Test com ...

  6. Node.js & module system

    Node.js & module system Node.js v10.9.0 Documentation https://nodejs.org/api/modules.html#module ...

  7. node.js module.exports & exports & module.export all in one

    node.js module.exports & exports & module.export all in one cjs const log = console.log; log ...

  8. Node.js & module.exports & exports

    Node.js & module.exports & exports https://www.cnblogs.com/xgqfrms/p/9493550.html exports &a ...

  9. Node.js module.exports和exports的区别

    require 用来加载代码,而 exports 和 module.exports 则用来导出代码,从接触node.js就不会它们两陌生,上代码: foo.js exports.a = functio ...

随机推荐

  1. WPF -- 使用当前进程打开自定义文件的一种方式

    问题描述 当双击打开自定义格式的文件时,希望使用当前正在运行的进程,而不是另起一个进程. 本文介绍一种方式解决如上问题,方案参考user3582780的解答 设置自定义文件格式的默认打开方式 参考链接 ...

  2. OO第四单元总结暨期末总结

    OO第四单元总结暨期末总结 目录 OO第四单元总结暨期末总结 第四单元三次作业架构与迭代 整体感受 HW1 HW2 HW3 四个单元架构设计与方法演进 Unit1 Unit2 Unit3 Unit4 ...

  3. 看过这篇剖析,你还不懂 Go sync.Map 吗?

    hi, 大家好,我是 haohongfan. 本篇文章会从使用方式和原码角度剖析 sync.Map.不过不管是日常开发还是开源项目中,好像 sync.Map 并没有得到很好的利用,大家还是习惯使用 M ...

  4. IDEA/JRebel实现内部/外部/远程Tomcat热部署Spring Boot

    1 概述 所谓热部署,对于Java应用程序来说,就是在运行时更新Java类文件.IDEA可以使用自带的Spring Boot热部署的方式进行本地/远程热部署,或者使用JRebel进行本地/远程热部署, ...

  5. Mysql 添加 create_time, update_time 创建时间 更新时间 自动更新

    # 添加 创建 更新 时间字段 ALTER TABLE `表名` ADD COLUMN `create_time`  datetime NOT NULL DEFAULT CURRENT_TIMESTA ...

  6. (九)Docker-PS 详解

    1. 作用 查看 docker 容器 2. 基本语法 docker ps [OPTIONS] OPTIONS说明: -a :显示所有的容器,包括未运行的. -f :根据条件过滤显示的内容. --for ...

  7. 我与OAuth 2.0那点荒唐的小秘密

    OAuth2.0这个名词你是否在项目中时常听到呢?是否觉得好像懂,又好像不太懂呢? 最近一直想写篇关于OAuth2.0的东西,记录下我的学习与感悟,然各种理由的拖延,直到今日才静下心来写下这篇博客.当 ...

  8. 深度解析Django REST Framework 批量操作

    我们都知道Django rest framework这个库,默认只支持批量查看,不支持批量更新(局部或整体)和批量删除. 下面我们来讨论这个问题,看看如何实现批量更新和删除操作. DRF基本情况 我们 ...

  9. text-align: justify 文本对齐

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. POJ1042 贪心钓鱼

    题意:       你有H小时(H*12个单位)时间去用,有n个鱼池在一条直线上,一开始你在1的位置,可以选择在某些鱼池上钓鱼,但是如果持续在一个鱼池上钓鱼钓鱼速度回成线性减少,初始每个时间单位钓fi ...