在NodeJS中,虽然模块与包这部分内容看似很简单,但是初学node,还是要把这部分内容搞懂,不然到后面学习NodeJS网络编程过程中会出现各种不好理解的错误。在这部分内容中,准备分两个章节
à模块与包基础部分
à模块与包深入部分。
模块与包基础部分
在这一部分中,我是用的参考书《Node.js开发指南》中奖的很详细,现总结学习笔记如下:
--------模块--------
路径问题
我的理解就如同java中的类文件。通过目录的索引方式索引。使用nodejs中提供的require函数来调用其他模块。模块都是基于文件的,在node中模块可以是javascript代码文件,json文件或编译过的CC++扩展
路径管理也同java的类似:
-
/.../.../xxx.js表示绝对路径
-
./xxx.js表示相对路径
-
不加/.../又不加./的话,则该模块要么是核心模块,要么是从 一个node_modules文件夹加载
在第三行中提到的核心模块即是nodejs本身提供的模块,也叫原生模块。这部分会在下面一个章节模块与包深入部分详细讲解。Mode_modules也叫做nodejs的中间件。比如我们要使用Express框架,npm –install –g express后,即可在文件中使用
-
var express = require('express');
require()
在我的使用过程中,在使用require()时要注意一点。在require('./xxxx')这条语句,可以使引入的一个xxx.js文件,也可以是引入的一个xxx目录的包。容易造成奇异,代码阅读的时候很容易混乱。在这里推荐,模块的引入最好加上xxx.js拓展名。
模块的创建及加载
1:在node中,通常一个文件就是一个模块。
文件和模块是一一对应的。在java中我们可以通过构造引入类的对象,通过对象访问类中的成员变量和方法。在node中通过在模块中生命的exports方法名来提供对外接口。创建module.js:
-
var name;
-
exports.setName = function(nameArg){
-
name = nameArg;
-
}
-
exports.sayHello = function(){
-
console.log('Hello '+name + '!');
-
}
在同一目录下创建getmodule.js
-
var myModule = require('./module.js');
-
myModule.setName('wenlonghor');
-
myModule.sayHello();
输出结果:Hello wenlonghor!
2:require的单次加载
Require通常不会重复加载模块,这跟node的加载机制有关,每一个模块都会有缓存,包括原生模块和自己新创建的模块。在这里只需要了解一下,在后面深入讲解模块与包的部分会有详细讲解。
-
var hello_01 = require('./module');
-
hello_01.setName('wenlonghor');
-
-
var hello_02 = require('./module');
-
hello_02.setName('HelloHor');
-
-
hello1.sayHello();
这时,输出结果:Hello HelloHor!
3:exports
Exports本身仅仅是一个普通的空对象{},本身咱们用来生命接口的,也相当于一个地址的引用。创建exports_test.js:
-
function MyHello(){ //创建一个名为MyHello的对象
-
var name;
-
this.setName = function(myName){
-
name = myName;
-
}
-
this.sayHello = function(){
-
console.log('Hello '+ name + "!");
-
}
-
}
-
exports.Hello = MyHello; //创建了一个对外接口Hello,这个接口指向MyHello对象。
当我们需要使用MyHello对象的时候:
-
var tmp = require('./export_test.js');
-
var obj_MyHello = tmp.Hello;
这里是显示的把Hello用不同种方式明明,来方便区分的。第一行中tmp获取的仅仅是exports接口对象,第二行通过tmp.Hello来获取exports接口对外提供的Hello借口,这个接口指向MyHello对象。即把MyHello对象赋值给obj_MyHello。
开发指南中还指明了另外一种方法来对MyHell对象提供对外接口:
-
function MyHello(){ //创建一个名为MyHello的对象
-
var name;
-
this.setName = function(myName){
-
name = myName;
-
}
-
this.sayHello = function(){
-
console.log('Hello '+ name + "!");
-
}
-
}
-
module.exports = MyHello;
通过上述方式,我们在获取MyHello对象的方式可以简化为:
-
var obj_MyHello = require('./exports_test.js');
具体的原理开发指南中所说的还不太明白,以后补上!
--------包-------
在讲包之前,先贴一个从npm中获取的express包,来看看包的结构:
从上述包结构并不是完全符合CommonJS的规范。这表明node对包的要求没有那么严格。只要这个包的根目录有package.json,并符合node对package.json的规范即可。接下来贴上express中package.json中的内容:
由于文件过长,只截取我们需要用到的内容即可。Main字段。上面章节已经提高过了,require()在引用的时候,可以不加拓展名。
Require('./xxx')。xxx如果是一个包,首先会检查包中的package.json中的main地段,将他作为包的接口模块,如果package.json不存在或者package.json中main字段不存在,会找当前包目根目录下的index.js或index.node作为包的接口。当然如果都没有找到,就会报异常了。。。
Package.json中dependencies:
这个是包的依赖关系,同样截取express的package.json中dependencies地段:
在这个字段中描述了express包中需要用到的相关第三方包。如果我们在安装express的时候npm会根据这个依赖关系添加到当前目录的node_modules中,也就是前面我们展示的express包结构截图。
Nodejs包管理器
在使用过nodejs的包管理器后发现比java中的要方便太多,相信用过sublimeText的也会有相同的经历,sublimeText的包管理器同nodejs的类似。
在讲包管理器之前需要先讲一个基础知识:本地模式和全局模式
-
//npm [install/i] -g [package_name],全局模式
-
npm install -g express
-
-
//npm [install/i] [package_name],本地模式
-
npm install express
通过全局模式安装的node包会放在如下图的目录下
使用全局模式的需求时,不止一个项目会用到它,不用在各个项目里面都单独加入这个模块,减少了模块的副本数量。全局模式需要在系统的环境变量上注册PATH。
需要注意的的一点是:使用全局模式安装的包并不能直接在javascript中使用require()直接获得。这个会在模块与包深入部分讲解。
与全局模式对应的是本地模式,本地模式就是在命令行的当前目录创建node_modules目录并把模块放入这个目录里面:
当然,上图所示的模块没有意义,因为我们自己建立的包是在test、test02等文件夹下。放置的cmd.exe是为了说明命令行的执行目录特意放在当前目录用于说明用的。通常情况下,本地模式实用的目录为当前项目的根目录,也就是package.json的同一级目录下面:
使用npm install自动获取依赖包
前面讲解package.json中有一个字段dependencies字段。我们在写自己的项目中如果用到express,或者mongodb的时候,除了上述的本地模式和全局模式手动安装相应的express包和mongodb包。也可以在dependencies字段中注明,然后在package.json的当前目录执行命令行
-
npm [install/i] [-g]
npm会自动解析dependencies字段中还没有的包,从npm的包管理中心(http://npmjs.org)搜索并下载包,安装在当前执行命令行的node_nodules子目录下。
Reference:
http://blog.sina.com.cn/s/blog_9f1c093101015cbo.html
http://jin541223.blog.163.com/blog/static/1637398052012111122751840/