您的位置:首页 > Web前端 > Node.js

Node中的模块机制

2013-12-23 09:14 302 查看
一、CommonJS地模块规范

CommonJS API定义了很多普通应用程序(主要指非浏览器的应用)使用的API,CommonJS API定义很多普通应用程序(主要指非浏览器的应用)使用的API,从而填补了这个空白。它的终极目标是提供一个类似Python,Ruby和Java标 准库。这样的话,开发者可以使用CommonJS API编写应用程序,然后这些应用可以运行在不同的JavaScript解释器和不同的主机环境中。

CommonJS对模块的定义十分简单,主要分为模块应用、模块定义和模块标识3个部分。

1、模块引用

模块引用的示例代码如下: var math = require(‘math’);

在CommonJS的规范中,存在require()方法,这个方法接受模块标识,以此引入-个模块的API到当前上下文中。

2、模块定义

在模块中,上一个下文提供require()方法来引入外部模块。对应引入的功能,上下文提供了exports对象用于导出当前模块的方法或者变量,并且它是唯一导出的出口。在模块中,还存在一个module对象,它代表模块自身,而exports是module的属性。在Node中,一个文件就是一个模块,将方法挂载在exports对象上作为属性即可定义导出的方式:

// math.js

exports.add = function() {

var sum = 0, i = 0, args = arguments, l = args.length;

while (i < l) { sum += args[i++]; } return sum;

};

在另一个文件中,我们通过require()方法引入模块后,就能调用定义的属性和方法了:

// test.js

var math = require(‘math’);

exports.increment = function (val) {

return math.add(val, 1);

}

3、模块标识

模块标识其实就是传递给require()方法的参数,它必须符合小驼峰命名的字符串,可以是相对路径和绝对路径的文件名,后缀js可以省略。

二、Node中模块和包

模块(Module)和包(Package)是Node.js最重要的支柱。Node.js的模块和包机制的实现参照了CommonJS的标准,但并不是完完全全遵循。不过区别不大

1、什么是模块

模块是Node.js应用程序的基本组成部分,文件和模块是一一对应的。换言之,一个Node.js文件就是一个模块。

再例如,我们要使用HTTP服务, var http = require(‘http’); 这里的http就是Node.js的一个核心模块。

2、创建和加载模块

我们知道什么是模块之后,我们再来看看如何创建并加载它们。

1)创建模块

在Node.js中,创建一个模块非常简单,因为一个文件就是一个模块。Node.js提供了exports和require两个对象,其中exports是模块公开的接口,require用于从外部获取一个接口,即所获取模块的exports对象。

新增文件module.js

var name;

exports.setName = function(theName) { name = theName; };

exports.setHello = function() { console.log(‘Hello ‘) + name; };

在同一目录下创建test.js

var myModule = require(‘./module’); myModule.setName(‘buzz’); myModule.sayHello();

输出 Hello buzz

2)加载模块—单次加载

上面这个例子有点类似创建一个对象,但是实际上和对象又有本质的区别,因为require不会重复加载。

修改test.js

var hello1 = requre(‘./module’);

hello1.setName (‘omelet’);

var hello2 = requre(‘./module’);

hello2.setName(‘buzztty’);

hell1.sayHello();

输出 Hello buzztty; 这是因为变量hello1和hello2指向的是同一个实例,因此hello1.setName被hello2.setName覆盖,最终输出结果是由后者决定的。

3)覆盖exprots

有时候我们只是想把一个对象封装到模块中,例如:obj.js

function Hello() {

var name;

this.setName = function (theName) {

name = theName;

};

this.sayHello = function () {console.log(‘Hello ‘ + name); };

}

exports.Hello = Hello;

如果我们需要引用上面的模块,那么就需要这样

requrie(‘./obj’).Hello来获取Hello对象,显得不是那么的精简

事实上,我们只需要将exports.Hello = Hello改为

module.exports = Hello

这样就可以直接获取这个对象了

我们现在使用它

var Hello = require(‘./hello’);

hello = new Hello();

hello.setName(‘tianhu’);

hello.sayHello();

注意,模块借口的唯一彼岸花是使用module.exports = Hello代替了exports.Hello= Hello.在外部引用该模块时,其接口对象就是要输出的Hello对象本身,而不是原先的exports.

事实上,exports本身仅仅是一个不同的空对象,即{},它专门用来声明接口。

3、创建包

先看一个严格的CommonSJ规范的包,应该具备以下特征:

package.json必须在包的顶层目录下

二进制文件应该在bin目录下

JavaScript代码应该在lib目录下

文档应该在doc目录下

单元测试应该在test目录下

Node.js并没有这么的规范,只要顶层目录下有package.json,并符合一些规范即可。

1)一个最简单的包

首先创建一个文件夹mypackage,在目录里面创建index.js内容如下:

exports.hello = function() {console.log(‘hello world’); }

然后在与mypackage同目录下新增test.js

var myPackage = require(‘./mypackage’);

mypackage.hello();

node test.js 输出 hello world

2) package.json

在mypackage目录下新增package.json并输入

{“main”:”/lib/interface.js”}

将index.js重命名为interface.js放入lib子目录下

node test.js 输出 hello world

Node.js在调用某个包时,会首先检查包中package.json文件的main字段,将其作为包的接口模块

如果package.json或main字段不存在,会尝试寻找index.js或index.node作为包的接口。

package.json是CommonJS规定的用来描述包的文件,完全符合贵伐的package.json文件因该包含有以下字段

name:包名称,不能有空格

description: 包的简要描述

version: 版本

keywords:关键字数组,用于搜索

maintainers:维护者

contributors:贡献者

bugs:提交bug地址

licenses:许可证

repositories:仓库托管地址数组,每个元素要包含type(创库类型,如git)、url(仓库的地址)和pth(相对于仓库的路径,可选)字段

dependencies:包的依赖,一个关系数组,由包名称和版本组成

下面是一个完完全全符合CommonJS规范的package.json示例:

{

“name” : “mypackage”,

“description”: “xxxxxx…”,

“version”:”0.7.0”,

“keywords”: [

“package”, “tinahu.peng"

],

“maintainers”:[ {

“name”:”buzztty”,

“email”:”buzztty@gmail.com”,}

],

“contributors:[

{

“name”: “kasjdfkl”

“email”: “akjsdfk@jakdjf"

}

],

“bugs” : {

“mail” : “skdjfkaj@akjfd”,

“url”:”http…"

},

“licenses”:[

“type”:”GPLv2”

“url”, “http://safkasdf"

],

“repositories”: [

{

“type” : “git”,

“url” : “http://github.com/buzztty/mypackage.git"

}

],

“dependencies”:{

“webkit” : ”1.2”,

“ssl” : {

“gnutls” : [“1.0”, “2.0”],

“openssl” : “0.9.8"

}

}

}

三、Node的模块实现

Node在现实中并没有完全按照规范实现,而是对规范进行了取舍,也增加了自身的特性。

1、在Node中,模块分为两种,一是Node提供的模块,称为核心模块;另外一种是用户编写的模块,称为文件模块

2、核心模块部分在编译和解析是最快的,因为我们在Node的编译中就完成了它们

3、文件模块是在运行时动态加载的,需要完整的路径分析、文件定位、编译执行过程、速度比核心模块慢;在我们指定文件模块的时候,不要让Node自己去找,而因该指定路径

4、如果不指定文件模块路径,它的顺序是当前路径、父目录下、父目录父目录下,看一个数组就明了了

[/root/myobj/buzz/abc/node_modules]

[/root/myobj/buzz/node_modules]

[/root/myobj/node_modules]

JavaScirpt核心模块的编译过程

1、Node采用了V8附带的js2c.py工具,将所有内置的JavaScript代码(src/node.js和lib/*.js)转化c++代码

2、进行编译

四、NPM包管理器

CommonJS包规范是理论,NPM是其中的一种实践

1、npm -v 可以查看npm的版本号

2、npm install express 安全包,是在当前目录下./node_modules/

3、npm install express -g 全局安装

全局模式并不是将一个模块安装为一个全局包的意思,它并不意味可以从任何地方通过require()来引用到它

-g是将一个包安装为全局可用的执行命令,它安装的目录是在/usr/local/lib/node_modules
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: