Node中的模块机制

一、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
          
    
     
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值