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
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
相关文章推荐
- Node.js中的模块机制学习笔记
- Node.js中的模块机制学习笔记
- 深入浅出Node.js(三):深入Node.js的模块机制
- 跟我学Node.js(四)---Node.js的模块载入方式与机制
- Angular Material串串学客户端开发 2 - Node.js模块加载机制Require()
- Node总结 模块机制
- Node.js入门:模块机制
- Nodejs 模块查找机制还不错(从当前目录开始逐级向上查找node_modules)
- 跟我学Node.js(四)---Node.js的模块载入方式与机制
- 游戏任务成就体系的实现(五):通讯模块(MsgUtil)基于NodeJS+TCP的机制的实现
- 深入浅出Node.js(三):深入Node.js的模块机制
- Node.js模块机制
- Node.js模块以及模块加载机制
- 学习Node.js模块机制
- Node.js的模块载入方式与机制
- node架构与模块机制
- 深入浅出Node.js(三):深入Node.js的模块机制
- 【深入浅出node.js】读书摘录2 - node.js模块机制
- Node.js的模块机制
- node模块机制与异步处理详解