什么是NodeJS
JS是脚本语言,脚本语言都需要一个解析器才能运行。对于写在HTML页面里的JS,浏览器充当了解析器的角色。而对于需要独立运行的JS,NodeJS就是一个解析器。
每一种解析器都是一个运行环境,不但允许JS定义各种数据结构,进行各种计算,还允许JS使用运行环境提供的内置对象和方法做一些事情。例如运行在浏览器中的JS的用途是操作DOM,浏览器就提供了document之类的内置对象。而运行在NodeJS中的JS的用途是操作磁盘文件或搭建HTTP服务器,NodeJS就相应提供了fs、http等内置对象。
什么是npm
npm是node packaged modules的缩写,其实是一个nodejs的module的管理工具
NPM提供了很多命令,例如install和publish,使用npm help可查看所有命令。
使用npm help 可查看某条命令的详细帮助,例如npm help install。
在package.json所在目录下使用npm install . -g可先在本地安装当前命令行程序,可用于发布前的本地测试。
使用npm update 可以把当前目录下node_modules子目录里边的对应模块更新至最新版本。
使用npm update -g可以把全局安装的对应命令行程序更新至最新版。
使用npm cache clear可以清空NPM本地缓存,用于对付使用相同版本号发布新版本代码的人。
使用npm unpublish @可以撤销发布自己发布过的某个版本代码。
在NodeJS中,一般将代码合理拆分到不同的JS文件中,每一个文件就是一个模块,而文件路径就是模块名。
在编写每个模块时,都有require、exports、module三个预先定义好的变量可供使用。
- require
require函数用于在当前模块中加载和使用别的模块,传入一个模块名,返回一个模块导出对象。模块名可使用相对路径(以./开头),或者是绝对路径(以/或C:之类的盘符开头)。另外,模块名中的.js扩展名可以省略。如下示范:
var foo1 = require('./foo'); var foo2 = require('./foo.js'); var foo3 = require('/home/user/foo'); var foo4 = require('/home/user/foo.js');
测试demo
新建一个count.js,该模块内部定义了一个私有变量i,并在exports对象导出了一个公有方法count
var i = 0; function count() { return ++i; } exports.count = count;
新建testCount.js
var counter1 = require('./count'); var counter2 = require('./count'); console.log(counter1.count()); console.log(counter2.count()); console.log(counter2.count());
运行testCount.js,控制台输出
1 2 3 [Finished in 0.6s]
可见,count.js并没有因为被require了两次而初始化两次。
- exports
exports对象是当前模块的导出对象,用于导出模块公有方法和属性。别的模块通过require函数使用当前模块时得到的就是当前模块的exports对象。以下例子中导出了一个公有方法。
exports.hello = function () { console.log('Hello World!'); };
也可写成如下格式:
function hello() { console.log('Hello World!'); }; exports.hello = hello;
- module
什么是module?所谓module和java中的包的概念很类似,一些解决方案的集合。
通过module对象可以访问到当前模块的一些相关信息,但最多的用途是替换当前模块的导出对象。例如模块导出对象默认是一个普通对象,如果想改成一个函数的话,可以使用以下方式。
module.exports = function () { console.log('Hello World!'); };
以上代码中,模块默认导出对象被替换为一个函数。
Nodejs 创建加载模块
在node.js中创建一个js文件就是创建一个模块。客户端Javascript使用script标签引入js文件就可以访问其内容。这样会带来一些弊端,比如作用域相同产生冲突的问题。
nodejs使用exports和require对象对外提供接口和引用模块。
一个简单的测试demo
(1)新建一个user.js
var userName = ''; function getUserName(){ return userName; } function setUserName(name){ userName = name; } //将需要被外界访问的定义到exports对象中 exports.getUserName = getUserName; exports.setUserName = setUserName;
(2)再新建一个test.js
//用require引用test.js var user = require('./user.js'); user.setUserName('TestMan'); console.log(user.getUserName());
(3)运行test.js,控制台输出
TestMan [Finished in 0.6s]
上面是将test.js里的希望对外提供访问的函数定义到exports对象。
如果是希望模块对外提供一个对象,而不是单独的函数,可以做如下调整
(1)修改user.js
var User = function(){ var userName = ''; this.setUserName = function(name){ userName = name; } this.getUserName = function(){ return userName } }; exports.User = User;
这样就对外提供了一个User类。
(2)将test.js也进行修改,修改成
var User = require('./user.js').User; var user = new User(); user.setUserName('TestMan'); console.log(user.getUserName());
(3)运行test.js,控制台输出
TestMan [Finished in 0.6s]
如果想将 User = require('./user.js').User;
优化成 User = require('./user.js');
这种格式的写法的话,可以对test.js进行修改
将原来的 exports.User = User;
修改成 module.exports = User;
修改user.js,如下:
var User = function(){ var userName = ''; this.setUserName = function(name){ userName = name; } this.getUserName = function(){ return userName } }; module.exports = User;
修改test.js,如下
var User = require('./user.js'); var user = new User(); user.setUserName('TestMan'); console.log(user.getUserName());
运行test.js,控制台输出
TestMan [Finished in 0.7s]
注:上面代码中的require('./user.js'),可以简化成require('./user');
module.exports与exports
module.exports才是模块公开的接口,每个模块都会自动创建一个module对象,对象有一个modules的属性,初始值是个空对象{},module的公开接口就是这个属性module.exports。
模块中会有一个exports对象,和module.exports指向同一个变量,所以修改exports对象的时候也会修改module.exports对象,module.exports对象不为空的时候exports对象就自动忽略是因为module.exports通过赋值方式已经和exports对象指向的变量不同了,exports对象怎么改和module.exports对象没关系了。
学习参考: