核心模块由一些精简高效的库组成,提供了基本的API
核心模块都是内置的,直接require即可
在浏览器JavaScript中,全局对象是window,在Node.js中,全局对象是global,所有全局变量(除global本身)都将成为global对象的属性,如console , process等
满足以下条件的变量将成为全局变量
在最外层定义的变量
全局对象的属性
未定义而直接赋值的变量(不使用var)
注:在node.js中,不可能在最外层定义变量,因为所有用户代码都是属于当前模块的,其作用域是当前模块的导出对象,这就是两个模块中的同名变量不冲突的原因
注:因此,在node.js中,使用var声明的变量永远不可能是全局变量,所以永远使用var来避免全局变量污染
process 是一个全局对象(global 对象的属性),可以在任何地方被访问,它用于描述当前Node.js 进程状态的对象,提供了一个与操作系统的简单接口(通常在写本地命令行程序的时候会用到)
返回一个包含命令行参数的数组(第一个元素会是 'node', 第二个元素将是 .js 文件的名称(包含路径),接下来的元素依次是命令行传入的参数)
标准输出流,console.log()就是对其的封装
process.stdout.write();
标准输入流,初始时它是被暂停的,要想从标准输入读取数据,必须恢复流,并手动编写流的事件响应函数
process.stdin.resume();
process.stdin.on('data', function(data) {
process.stdout.write('你输入了: ' + data.toString());
});
为事件循环设置一项任务,Node.js 会在下次事件循环调响应时调用 callback
用于提供控制台标准输出
console.log(); //向标准输出流打印字符
console.error(); //向标准输出流输出错误
console.trace(); //向标准输出流输出当前调用栈
util模块提供常用函数的集合,用于弥补Core JavaScript功能过于精简的不足
使用util模块前先加载该模块
var util = require(‘util’); //加载模块
该方法实现对象间原型继承
第一个参数是一个构造函数
第二个参数是一个需要继承的构造函数
注:第一个构造函数可以继承第二个构造函数的原型中的属性
JavaScript 的面向对象特性是基于原型的, JavaScript 没有提供对象继承的语言级别特性,而是通过原型复制来实现的
function Base(){
this.name="china";
this.age= 2014;
this.sayHello=function(){
console.log(this.name);
};
}
Base.prototype.job="code";
function Sub(){
this.name="shandong";
}
util.inherits(Sub,Base);
var s = new Sub();
console.log(s.name); //shandong
console.log(s.age); //undefined
console.log(s.job); //code
注意,Sub 仅仅继承了Base 在原型中定义的属性
该方法将任意对象转换为字符串
第一个参数,必须,表示要转换的对象
第二个参数,可选,布尔值,表示是否输出更多隐藏信息
第三个参数,可选,表示递归层次(指定为null,完整遍历整个对象)
第四个参数,可选,布尔值,表示是否在控制台高亮显示
注:该方法转换字符串时,并不会调用对象的toString()方法
判断一个对象是不是数组
判断一个对象是不是正则表达式
判断Date类型
判断Error类型
Node.js是事件驱动的,而events提供了唯一的接口,events 模块不仅用于用户代码与 Node.js 下层事件循环的交互,还几乎被所有的模块依赖
以往在浏览器端,事件来源于DOM和BOM,Node中不存在DOM和BOM,所以自己创建了EventEmitter类型来实现事件的基本功能
events模块只提供了一个对象: events.EventEmitter。EventEmitter 的核心就是事件发射与事件监听器功能的封装
var EventEmitter= require("events").EventEmitter;
var event= new EventEmitter(); //EventEmitter是一个类,要创建实例化对象
这两个方法实现了事件监听的功能
第一个参数,必须,监听的事件名字符串
第二个参数,必须,回调函数
emitter.on("eventName",function(){
});
注:同一事件名可以绑定若干个事件监听器。当事件发射时,注册到这个事件的事件监听器被依次调用
once()实现事件监听,参数同上,但只注册了一个单次监听器
emitter.once("eventName",function(){
});
emit()实现了触发事件的功能
第一个参数,必须,触发的事件名字符串(对应于监听的事件名)
第2~n个参数,可选,回调函数的参数
emitter.emit("eventName");
还有一个特殊的事件error,它包含了“错误”的语义,在遇到异常的时候通常会发射 error 事件
注:error事件不需要显式监听
注:触发error事件必须要有回调函数,否则程序会崩溃
var events = require('events');
var emitter = new events.EventEmitter();
emitter.emit('error' , function(){ });
removeListener()实现了移除指定事件监听器的功能
第一个参数,必须,事件名字符串,对应于监听的事件名
第二个参数,必须,回调函数(监听器)
removeAllListener()实现了移除所有事件监听器的功能
一个参数,可选,事件名字符串,对应于监听的事件名
注:大多数时候我们不会直接使用events.EventEmitter,而是在对象中继承它(包括fs、http在内,只要是支持事件响应的核心模块都是EventEmitter的子类)
为什么要这样做呢?原因有两点:
首先,具有某个实体功能的对象实现事件符合语义,事件的监听和发射应该是一个对象的方法。
其次JavaScript 的对象机制是基于原型的,支持部分多重继承,继承EventEmitter不会打乱对象原有的继承关系
fs模块是文件操作的封装,它提供了文件的读取、写入、更名、删除、遍历目录、链接等操作
注:与其他模块不同,fs 模块中所有的操作都提供了异步的和同步两个版本
var fs = require(“fs”); //引入模块
异步读取文件,无返回值
第一个参数,必须,表示要读取的文件路径及文件名
第二个参数,可选,表示以何种字符编码解析文件
第三个参数,可选,表示回调函数,接收两个参数,第一个参数必须是错误信息,第二个参数才表示文件内容
fs.readFile('test.txt' , 'utf-8' , function(err,data){
if(err){
console.error(err);
}else{
console.log(data);
}
});
console.log('end'); //先输出'end',再输出文件内容
注:虽然可以不指定编码方式,但是这样的话读取到的就是二进制数据,这通常不是我们想要的(可以data.toString()),所以要记得指定编码方式,而且指定编码方式后,读取到的都字符串
注:Node.js 的异步编程接口习惯是以函数的最后一个参数为回调函数,通常一个函数只有一个回调函数。回调函数是实际参数中第一个是 err,其余的参数是其他返回的内容。如果没有发生错误, err 的值会是 null 或undefined。如果有错误发生, err 通常是 Error 对象的实例
同步读取读取文件,会阻塞,返回读取到的内容(或者报错)
第一个参数,必须,表示要读取的文件名
第二个参数,可选,表示以何种字符编码解析文件
var con = fs.readFileSync('test.txt' , 'utf-8');
console.log(con);
同步版读取到的内容以函数返回值的形式返回,当发生错误时会以通常的抛出错误的形式返回错误(当然可以使用try-catch来捕获错误)
而异步版大多没有返回值,但需要一个回调函数作为最后一个参数传入。且回调函数的第一个形参为返回的错误信息。 如果异步操作执行正确并返回,该错误形参则为null或者undefined。而读取到的内容作为回调函数的第二个参数
同步版本会阻塞进程,直到完成处理
异步版本不阻塞,但不能保证执行顺序,想要保证按顺序执行,需在回调函数里完成下一步
异步读取文件,无返回值
异步打开文件
第一个参数,必须,表示要打开的文件名
第二个参数,必须,表示打开方式
r :以读取模式打开文件
r+ :以读写模式打开文件
w :以写入模式打开文件,如果文件不存在则创建
w+ :以读写模式打开文件,如果文件不存在则创建
a :以追加模式打开文件,如果文件不存在则创建
a+ :以读取追加模式打开文件,如果文件不存在则创建
第三个参数,可选,表示文件权限
第四个参数,可选,表示回调函数,接收两个参数,第一个参数必须是错误信息,第二个参数表示文件描述符
var fs = require('fs');
fs.open("./test.txt",'r',function(err,des){
console.log(des)
});
小文件拷贝示例
var fs = require('fs');
function copy(src, dst) {
fs.writeFileSync(dst, fs.readFileSync(src));
}
function main(argv) {
copy(argv[0], argv[1]);
}
main(process.argv.slice(2));
拷贝一些小文件没啥问题,但这种一次性把所有文件内容都读取到内存中后再一次性写入磁盘的方式不适合拷贝大文件,内存会爆仓。对于大文件,我们只能读一点写一点,直到完成拷贝。因此上边的程序需要改造如下。
var fs = require('fs');
function copy(src, dst) {
fs.createReadStream(src).pipe(fs.createWriteStream(dst));
}
function main(argv) {
copy(argv[0], argv[1]);
}
main(process.argv.slice(2));
以上程序使用fs.createReadStream创建了一个源文件的只读数据流,并使用fs.createWriteStream创建了一个目标文件的只写数据流,并且用pipe方法把两个数据流连接了起来。连接起来后发生的事情,说得抽象点的话,水顺着水管从一个桶流到了另一个桶。