- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Node.js模块加载详解由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
JavaScript是世界上使用频率最高的编程语言之一,它是Web世界的通用语言,被所有浏览器所使用。JavaScript的诞生要追溯到Netscape那个时代,它的核心内容被仓促的开发出来,用以对抗Microsoft,参与当时白热化的浏览器大战。由于过早的发布,无可避免的造成了它的一些不太好的特性.
尽管它的开发时间很短,但是JavaScript依然具备了很多强大的特性,不过,每个脚本共享一个全局命名空间这个特性除外.
一旦Web页面加载了JavaScript代码,它就会被注入到全局命名空间,会和其他所有已加载的脚本公用同一个地址空间,这会导致很多安全问题,冲突,以及一些常见问题,让bug即难以跟踪又很难解决.
不过谢天谢地,Node为服务器端JavaScript定了一些规范,还实现了CommonJS的模块标准,在这个标准里,每个模块有自己的上下文,和其他模块相区分。这意味着,模块不会污染全局作用域,因为根本就没有所谓的全局作用域,模块之间也不会相互干扰.
本章,我们将了解几种不同的模块以及如何加载它们.
把代码拆分成一系列定义良好的模块可以帮你掌控你的应用程序,下面我们将学习如何创建和使用你自己的模块.
了解Node如何加载模块 。
Node里,可以通过文件路径来引用模块,也可以通过模块名引用,如果用名称引用非核心模块,Node最终会把模块名影射到对应的模块文件路径。而那些包含了核心函数的核心模块,会在Node启动时被预先加载.
非核心模块包括使用NPM(Node Package Manager)安装的第三方模块,以及你或你的同事创建的本地模块.
每个被当前脚本导入的模块都会向程序员暴露一组公开API,使用模块前,需要用require函数来导入它,像这样:
。
上面的代码会导入一个名为module_name的模块,它可能是个核心模块,也可以是用NPM安装的模块,require函数返回一个包含模块所有公共API的对象。随模块的不同,返回的对象可能是任何JavaScript值,可以是一个函数,也可以是个包含了一系列属性(函数,数组或者任何JavaScript对象)的对象.
导出模块 。
CommonJS模块系统是Node下文件间共享对象和函数的唯一方式。对于一个很复杂的程序,你应该把一些类,对象或者函数重构成一系列良好定义的可重用模块。对于模块使用者来说,模块仅对外暴露出那些你指定的代码.
在下面的例子里你将会了解到,在Node里文件和模块是一一对应的,我们创建了一个叫circle.js的文件,它仅对外导出了Circle构造函数.
。
function r_squared() { 。
return Math.pow(r, 2),
} 。
function area() { 。
return Math.PI * r_squared(),
} 。
return {area: area},
} 。
module.exports = Circle,
。
代码里最重要的是最后一行,它定义了模块对外导出了什么内容。module是个特殊的变量,它代表当前模块自身,而module.exports是模块对外导出的对象,它可以是任何对象,在这个例子里,我们把Circle的构造函数导出了,这样模块使用者就可以用这个模块来创建Circle实例.
你也可以导出一些复杂的对象,module.exports被初始化成一个空对象,你把任何你想暴露给外界的内容,作为module.exports对象的属性来导出。比如,你设计了一个模块,它对外暴露了一组函数:
。
console.log('A'),
} 。
function printB() { 。
console.log('B'),
} 。
function printC() { 。
console.log('C'),
} 。
module.exports.printA = printA,
module.exports.printB = printB,
module.exports.pi = Math.PI,
。
这个模块导出了两个函数(printA和printB)和一个数字(pi),调用代码看起来像这样:
。
myModule2.printA(); // -> A 。
myModule2.printB(); // -> B 。
console.log(myModule2.pi); // -> 3.141592653589793 。
。
加载模块 。
前面提到过,你可以使用require函数来加载模块,不用担心在代码里调用require会影响全局命名空间,因为Node里就没有全局命名空间这个概念。如果模块存在且没有任何语法或初始化错误,require函数就会返回这个模块对象,你还可以这个对象赋值给任何一个局部变量.
模块有几种不同的类型,大概可以分为核心模块,本地模块和通过NPM安装的第三方模块,根据模块的类型,有几种引用模块的方式,下面我们就来了解下这些知识.
加载核心模块 。
Node有一些被编译到二进制文件里的模块,被称为核心模块,它们不能通过路径来引用,只能用模块名。核心模块拥有最高的加载优先级,即使已经有了一个同名的第三方模块,核心模块也会被优先加载.
比如,如果你想加载和使用http核心模块,可以这样做:
。
这将返回一个包含了http模块对象,它包含了Node API文档里定义的那些htpp模块的API.
加载文件模块 。
你也可以使用绝对路径从文件系统里加载模块:
。
。
。
var myModule2 = require('./lib/my_module_2'),
。
注意上面的代码,你可以省略文件名的扩展名,如果Node找不到这个文件,会尝试在文件名后加上js后缀再次查找(译者注:其实除了js,还会查找json和node,具体可以看官网文档),因此,如果在当前目录下存在一个叫my_module.js的文件,会有下面两种加载方式:
。
。
var myModule = require('./my_module.js'),
。
加载目录模块 。
你还可以使用目录的路径来加载模块:
。
Node会假定这个目录是个模块包,并尝试在这个目录下搜索包定义文件package.json.
如果没找到,Node会假设包的入口点是index.js文件(译者注:除了index.js还会查找index.node,.node文件是Node的二进制扩展包,具体见官方文档),以上面代码为例,Node会尝试查找./myModuleDir/index.js文件.
反之,如果找到了package.json文件,Node会尝试解析它,并查找包定义里的main属性,然后把main属性的值当作入口点的相对路径。以本例来说,如果package.json定义如下:
。
"name" : "myModule".
"main" : "./lib/myModule.js" 。
} 。
。
Node就会尝试加载./myModuleDir/lib/myModule.js文件 。
从node_modules目录加载 。
如果require函数的参数不是相对路径,也不是核心模块名,Node会在当前目录的node_modules子目录下查找,比如下面的代码,Node会尝试查找文件./node_modules/myModule.js
。
你可以使用这个特性来管理node_modules目录的内容或模块,不过最好还是把模块的管理任务交给NPM(见第一章),本地node_modules目录是NPM安装模块的默认位置,这个设计把Node和NPM关联在了一起。通常,作为开发人员不必太关心这个特性,你可以简单的使用NPM安装,更新和删除包,它会帮你维护node_modules目录 。
缓存模块 。
模块在第一次成功加载后会被缓存起来,就是说,如果模块名被解析到同一个文件路径,那么每次调用require(‘myModule')都确切地会返回同一个模块.
比如,有一个叫my_module.js的模块,包含下面的内容:
。
module.exports = function() { 。
console.log('Hi!'),
},
console.log('my_module initialized.'),
。
然后用下面的代码加载这个模块:
。
。
它会产生下面的输出:
。
。
my_module initialized 。
。
如果我们两次导入它:
。
。
var myModuleInstance2 = require('./my_module'),
。
输出依然是:
。
。
my_module initialized 。
。
也就是说,模块的初始化代码仅执行了一次。当你构建自己的模块时,如果模块的初始化代码里含有可能产生副作用的代码,一定要特别注意这个特性.
小结 。
Node取消了JavaScript的默认全局作用域,转而采用CommonJS模块系统,这样你可以更好的组织你的代码,也因此避免了很多安全问题和bug。可以使用require函数来加载核心模块,第三方模块,或从文件及目录加载你自己的模块 。
还可以用相对路径或者绝对路径来加载非核心模块,如果把模块放到了node_modules目录下或者对于用NPM安装的模块,你还可以直接使用模块名来加载.
译者注:
建议读者把官方文档的模块章节阅读一遍,个人感觉比作者讲得更清晰明了,而且还附加了一个非常具有代表性的例子,对理解Node模块加载会很有很大帮助。下面把那个例子也引用过来:
。
。
1. 如果X是核心模块.
a. 加载并返回核心模块 。
b. 结束 。
2. 如果X以 './' or '/' or '../ 开始' 。
a. LOAD_AS_FILE(Y + X) 。
b. LOAD_AS_DIRECTORY(Y + X) 。
3. LOAD_NODE_MODULES(X, dirname(Y)) 。
4. 抛出异常:"not found" 。
LOAD_AS_FILE(X) 。
1. 如果X是个文件,把 X作为JavaScript 脚本加载,加载完毕后结束 。
2. 如果X.js是个文件,把X.js 作为JavaScript 脚本加载,加载完毕后结束 。
3. 如果X.node是个文件,把X.node 作为Node二进制插件加载,加载完毕后结束 。
LOAD_AS_DIRECTORY(X) 。
1. 如果 X/package.json文件存在.
a. 解析X/package.json, 并查找 "main"字段. 。
b. 另M = X + (main字段的值) 。
c. LOAD_AS_FILE(M) 。
2. 如果X/index.js文件存在,把 X/index.js作为JavaScript 脚本加载,加载完毕后结束 。
3. 如果X/index.node文件存在,把load X/index.node作为Node二进制插件加载,加载完毕后结束 。
LOAD_NODE_MODULES(X, START) 。
1. 另DIRS=NODE_MODULES_PATHS(START) 。
2. 对DIRS下的每个目录DIR做如下操作
a. LOAD_AS_FILE(DIR/X) 。
b. LOAD_AS_DIRECTORY(DIR/X) 。
NODE_MODULES_PATHS(START) 。
1. 另PARTS = path split(START) 。
2. 另ROOT = index of first instance of "node_modules" in PARTS, or 0 。
3. 另I = count of PARTS - 1 。
4. 另DIRS = [] 。
5. while I > ROOT.
a. 如果 PARTS[I] = "node_modules" 则继续后续操作,否则下次循环 。
c. DIR = path join(PARTS[0 .. I] + "node_modules") 。
b. DIRS = DIRS + DIR 。
c. 另I = I - 1 。
6. 返回DIRS 。
最后此篇关于Node.js模块加载详解的文章就讲到这里了,如果你想了解更多关于Node.js模块加载详解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
全称“Java Virtual Machine statistics monitoring tool”(statistics 统计;monitoring 监控;tool 工具) 用于监控虚拟机的各种运
主要是讲下Mongodb的索引的查看、创建、删除、类型说明,还有就是Explain执行计划的解释说明。 可以转载,但请注明出处。  
1>单线程或者单进程 相当于短链接,当accept之后,就开始数据的接收和数据的发送,不接受新的连接,即一个server,一个client 不存在并发。 2>循环服务器和并发服务器
详解 linux中的关机和重启命令 一 shutdown命令 shutdown [选项] 时间 选项: ?
首先,将json串转为一个JObject对象: ? 1
matplotlib官网 matplotlib库默认英文字体 添加黑体(‘SimHei')为绘图字体 代码: plt.rcParams['font.sans-serif']=['SimHei'
在并发编程中,synchronized关键字是常出现的角色。之前我们都称呼synchronized关键字为重量锁,但是在jdk1.6中对synchronized进行了优化,引入了偏向锁、轻量锁。本篇
一般我们的项目中会使用1到2个数据库连接配置,同程艺龙的数据库连接配置被收拢到统一的配置中心,由DBA统一配置和维护,业务方通过某个字符串配置拿到的是Connection对象。  
实例如下: ? 1
1. MemoryCahe NetCore中的缓存和System.Runtime.Caching很相似,但是在功能上做了增强,缓存的key支持object类型;提供了泛型支持;可以读缓存和单个缓存
argument是javascript中函数的一个特殊参数,例如下文,利用argument访问函数参数,判断函数是否执行 复制代码 代码如下: <script
一不小心装了一个Redis服务,开了一个全网的默认端口,一开始以为这台服务器没有公网ip,结果发现之后悔之莫及啊 某天发现cpu load高的出奇,发现一个minerd进程 占了大量cpu,googl
今天写这个是为了 提醒自己 编程过程 不仅要有逻辑 思想 还有要规范 代码 这样可读性 1、PHP 编程规范与编码习惯最主要的有以下几点: 1 文件说明 2 funct
摘要:虚拟机安装时一般都采用最小化安装,默认没有lspci工具。一台测试虚拟网卡性能的虚拟机,需要lspci工具来查看网卡的类型。本文描述了在一个虚拟机中安装lspci工具的具体步骤。 由于要测试
1、修改用户进程可打开文件数限制 在Linux平台上,无论编写客户端程序还是服务端程序,在进行高并发TCP连接处理时,最高的并发数量都要受到系统对用户单一进程同时可打开文件数量的限制(这是因为系统
目录 算术运算符 基本四则运算符 增量赋值运算符 自增/自减运算符 关系运算符 逻
如下所示: ? 1
MapperScannerConfigurer之sqlSessionFactory注入方式讲解 首先,Mybatis中的有一段配置非常方便,省去我们去写DaoImpl(Dao层实现类)的时间,这个
Linux的网络虚拟化是LXC项目中的一个子项目,LXC包括文件系统虚拟化,进程空间虚拟化,用户虚拟化,网络虚拟化,等等,这里使用LXC的网络虚拟化来模拟多个网络环境。 本文从基本的网络设备讲
? 1
我是一名优秀的程序员,十分优秀!