node.js是一个基于chrome V8 引擎的JavaScript运行时。
就是说这个node.js可以用来运行js文件,这样我们就不需要在浏览器里运行js文件,只需在node中,大大方便了我们的开发。
首先,大家就需要去安装好node,配置好环境变量,那么我们就可以开始学习node之旅。
node的中文官网 http://nodejs.cn/api/
我们先来讲解node的全局变量,当然我们不可能全部讲,找些重点和常用的
__dirname__filename定时器进程对象global__dirname(前面有两个下划线):表示获取当前js的文件夹地址,包括自己
console.log(__dirname);--->C:\Users\gyh\Desktop\day2\01.js 01.js就是自己__filename(前面有两个下划线):表示获取当前js的文件夹的地址,不包括自己
console.log(__filename);--->C:\Users\gyh\Desktop\day2 相比较于__dirname少了01.js,就是地址里面不包括自己定时器:
var timer = setTimeout(function() { console.log("setTimeout"); },1000); var timer1 = setInterval(function(){ console.log("setInterval") },1000); //定时器的用法和js一样没差别进程对象:
console.log(process.argv);// 线程 进程 一个进程可以含多个线程 一个线程就是程序执行的路径 console.log(process.arch); //当前系统的架构 32/64global:全局变量
在node中是没有window的全局对象的,所以我们是无法使用window.alert("xxx"),在node中全局变量就是global,当然全局变量是可以省略的
global.console.log(12345); console.log(12345);为什么我们要学习模块化?比如说有这么一个应用场景,a.js需要调用b.js的方法?那么我们需要如何去应用b.js的方法呢?这时候我们就是用将b.js模块化。
导出模块有两种方式
exports.xxx=xxxmodule.exports=xxx两中导出方法是有差异的,并且导出方法的不同那么调用方法也是不同的
1.exports.xxx=xxx
//模块b.js function sum(a,b){ return a+b; } //导出模块 exports.sum = sum; //a.js使用b.js的sum方法 var b = require("./b.js"); var res = b.sum(1,2); console.log(res);2.module.exports=xxx
//模块b.js function sum(a,b){ return a+b; } //导出模块 module.exports= sum; //a.js使用b.js的sum方法 var b = require("./b.js"); console.log(b(1,2));上面两种方法的值都是3
我们可以看到两种方法的导出方式不同导致调用的方式也不同。那么两者到底有什么区别呢?下面我们来讲解一下
需要注意的是module.exports和exports这两种方式是不能同时使用的,也就是说只能二选一。
我们可以把两种方式写成一个关系式
module.exports = {}
exports = {}
module.exports===exports--->true
也就是说module.exports和exports所表示的对象是同一个对象,所以会有两种导出的方式。
这也就是为什么最后我们调用的方式不同,因为exports我们是在该对象里添加参数,而module.exports则是重新赋予一个新的对象。
那么我们会问了,为什么我们不能给exports的方法去赋予一个对象?那么我们来试一试。
//模块b.js function sum(a,b){ return a+b; } //导出模块 exports= sum; //a.js使用b.js的sum方法 var b = require("./b.js"); var res = b(1,2); console.log(res);结果是报错,说找不到该方法。为什么呢?我们不是给exports赋予了一个到处对象?里面不就有方法,为什么还是找不到该方法?
因为是这样子的,导出对象虽然有两种方法,但是最后还是以module.exports所指向的对象为主,一开始exports和module.exports指向的是同一个对象,所以你在给exports的对象添加参数的同时,他们指向的对象至始至终都是同一个,但若你要改变exports的指向对象,而实际导出的却又是module.exports的对象,此时exports和module.exports指向的是两个对象,所以在调用的时候会找不到该方法。
通过线面模板的导出有了一些认识之后,我们来学习一下node给我们的path模块。
如何引入模块?
var path = require("path"); ------所有node的模块引入都是 require(xxx);
path模块是干什么的呢?主要是用来操作路径的
basenamedirnameextnameformatparseisAbsolutejoinnormalizerelativeresolvebasename
表示获取路径的最后一个部分
const path = require("path"); path.basename('foo/bar/baz/asdf/quux.html');// quux.html path.basename('foo/bar/baz/asdf/quux.html',".html"); // quux path.basename('foo/bar/baz/asdf/quux.html',"html"); // quux. path.basename('foo/bar/baz/asdf/quux.html',".txt");// quux.html第二个参数表示是过滤掉同样后缀的那部分,就第二个参数的".html",则在结果中忽略".html",若是"html",则忽略"html".
dirname
表示返回当前路径的路径名
const path = require("path") path.dirname("/a/b/c/d");// /a/b/cextname
表示返回path路径中最后一个部分从.(句号)开始到字符串结束的内容
const path = require("path"); path.extname('foo/bar/baz/asdf/quux.html');// .html path.extname('foo/bar/baz/asdf/quux.txt'); // .txt path.extname('foo/bar/baz/asdf/quux.txt.java'); // .java path.extname('foo/bar/baz/asdf/quux.'); // . path.extname('foo/bar/baz/asdf/quux');// 返回空字符串parse
该方法就是把一个path的路径转化为一个pathObject对象
const path = require("path"); path.parse(__dirpath); { root: 'C:\\', dir: 'C:\\Users\\gyh\\Desktop', base: 'day4', ext: '', //因为没有后缀名所以为空 name: 'day4' }format
该方法和parse相对,就是把pathObject对象转化为path的string。
const path = require("path"); let data = { root: 'C:\\', dir: 'C:\\Users\\gyh\\Desktop', base: 'day4.txt', ext: '.txt', name: 'day4' } console.log(path.format(data));//C:\Users\gyh\Desktop\day4.txtisAbsolute
判断给的路径是不是绝对路径
const path = require("path"); path.isAbsolute('//server'); // true path.isAbsolute('\\\\server'); // true path.isAbsolute('C:/foo/..'); // true path.isAbsolute('C:\\foo\\..'); // true path.isAbsolute('bar\\baz'); // false path.isAbsolute('bar/baz'); // false path.isAbsolute('.'); // falsejoin
表示拼接路径,路径必须是字符串
const path = require("path"); console.log(path.join('/foo','bar','asc/fg','he','../../'));//\foo\bar\asc\ console.log(path.join('/foo','bar','asc/fg','he','..'));//\foo\bar\asc\\fg console.log(path.join('/foo','bar','asc/fg','he'));//\foo\bar\asc\gf\he console.log(path.join('/foo','bar','asc/fg/','he'));//\foo\bar\asc\gf\he console.log(path.join('/foo','bar','asc/fg/',{},'he'));// 报错..表示返回到上一级目录
normalize
表示规范路径。就是会将很多连续的分隔符统一变成规范的。
path.win32.normalize('C:temp\\\\/\\/\\/foo/bar');// 'C:\\temp\\foo\\bar' path.normalize('C:\\temp\\\\foo\\bar\\..\\');// 'C:\\temp\\foo\\' path.normalize('/foo/bar//baz/asdf/quux/..');// '/foo/bar/baz/asdf'relative(from,to)
表示from路径相对于to路径的相对路径
path.relative('C:\\orandea\\test\\aaa', 'C:\\orandea\\impl\\bbb');// 返回: '..\\..\\impl\\bbb'resolve
将多个路径片段,解析成一个绝对路径
console.log(path.resolve('wwwroot','static_files/png/','../gif/img.gif')); //C:\Users\gyh\Desktop\day4\wwwroot\static_files\gif\img.gif当前路径是C:\Users\gyh\Desktop\day4,在这个基础上拼接wwwroot->C:\Users\gyh\Desktop\day4\wwwroot,然后在这基础上再添加static_files/png/--->C:\Users\gyh\Desktop\day4\wwwroot\static_files/png,最后返回上一级,找到git的img.gif-->//C:\Users\gyh\Desktop\day4\wwwroot\static_files\gif\img.gif
fs模块是文件系统模块,同样的本文也只是介绍些常用的方法,不会讲所有方法一一讲解一遍。
stat
readFile
writeFile
mkdir
readdir
rmdir
createReadStream
createWriteStream
stat(url,callback)
表示获取文件状态。
url当然就是路径了,callback这个回调函数里有两个参数,一个是error,一个是stats。前者表示当获取文件状态发生异常时,error不会空,并且error.code错误码来表示某种错误。stats则表示文件状态,是一个对象。如下
Stats { dev: 1759477673, mode: 16822, nlink: 1, uid: 0, gid: 0, rdev: 0, blksize: undefined, ino: 1125899907036429, size: 0, blocks: undefined, atimeMs: 1540557316105.3225, mtimeMs: 1540557316105.3225, ctimeMs: 1540557316105.3225, birthtimeMs: 1540557316101.1113, atime: 2018-10-26T12:35:16.105Z, mtime: 2018-10-26T12:35:16.105Z, ctime: 2018-10-26T12:35:16.105Z, birthtime: 2018-10-26T12:35:16.101Z }就比如说size就是表示文件的大小,birthtime表示被创建的时间,birthtimeMs表示被创建的毫秒时间。该对象还有一些方法
stats.isFile() 表示是否是一个普通文件,stats.isDirectory()表示是否是一个文件夹。stat的具体使用如下
const fs = require("fs"); console.log(1); fs.stat("./my",function(error,stat){ if(stat.isFile()){ console.log("isflie"); }else{ console.log("dir"); } console.log(2); console.log(stat); }) console.log(3);首先stat是异步的,所以log的输出顺序是
如果想要同步获取那么就使用statSync
const fs = require("fs"); // statSync 同步 let fs_sy = fs.statSync("./my");返回的结果就是stats对象
readFile(url[,options],callback)
表示异步的读取一个文件的内容。
const fs = require("fs"); fs.readFile(__dirname+"/my/demo.txt",{encoding:"utf8",flag:"r"},(error,data)=>{ if(error){ console.log(error); return; } console.log(data.toString()); })options其实是一个对象,encoding表示字符编码,flag表示文件系统的flag,如r就表示可读。
同样的callback回调返回两个参数,一个是error在读取文件发生错误时返回的信息,data则是读取到的信息。
readFile这是异步的,但也有同步方法也是就是readFileSync,那么返回的结果就是读取的数据
writeFile(url,data[,options],callback)
表示异步给文件写入指定数据
const fs = require("fs"); let strpath = path.join(__dirname,"./my/demo.txt"); fs.writeFile(strpath,"hello word1111","utf8",function(err){ if (err) { console.log(err); }else{ console.log("文件写入成功"); } })options表示一个对象,有三个参数,encoding表示字符编码,flag表示文件系统flag,mode表示文件的权限,当输入字符串时默认视为encoding。
此时的callback回调只返回一个error。
同样的写入数据可以同步就是writeFileSync,返回的是underfined。同步也好异步也好当找不到要写入的文件的时候,都回去创建该文件。
mkdir
该方法是异步创建文件夹
const fs = require("fs"); //添加文件夹 fs.mkdir("./mkdir",(err)=>{ console.log(err); })同样的该方法是异步的,想要同步创建文件及则用mkdirSync方法
readdir
该方法则是用来遍历指定目录下所有文件。
const fs = require("fs"); //遍历目录 fs.readdir(__dirname,(err,fils)=>{ if(err){ return ; } console.log(fils); })我们可以来看看输出
[ 'jquery-1.12.4.js', 'my', 'my.rar', 'myhtml.html', 'myjs.js', 'myjs1.js', 'myjs2.js', 'myjs3.js', 'myjs4.js' ]连文件类型都是会显示出来的
rmdir
该方法和mkdir对应,就是删除文件夹
const fs = require("fs"); //删除文件 fs.rmdir(path.join(__dirname,"mkdir"),(err)=>{ console.log(err); })createReadStream
将一个文件的内容解析成输入数据流,并返回该数据流 readStream。
const fs = require("fs"); const path = require("path"); //大文件的转数据流 let readStream = fs.createReadStream("./my/demo.txt","utf8"); //解析数据流,给流绑定解析时间 readStream.on("data",(chunk)=>{ console.log(chunk.length); console.log(chunk); }) //给流绑定数据被解析完的回调 readStream.on("end",()=>{ console.log("is end"); })createWriteStream
将一个文件解析成一个输出数据流,并返回该数据流,writeStream
const fs = require("fs"); const path = require("path"); //大文件的操作 let readStream = fs.createReadStream("./my.rar"); let writeStream = fs.createWriteStream("./my_write.rar"); readStream.on("data",(chunk)=>{ //解析数据 console.log(chunk.length); writeStream.write(chunk); //方法1:将解析出来的数据写入到输出流中 }) readStream.on("end",()=>{ console.log("is end"); }) readStream.pipe(writeStream);//方法2:将输入流和输出流相绑定平时在开发项目中,我们都需要去创建很多文件比如说css img js 等,现在我们就可以通过path和fs模块去快递生产这些基本项目结构。
const fs = require("fs"); const path = require("path"); let index_content = ` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> </body> </html> `; const root = __dirname; let pathData = { rootName:"buildDemo", data:[{ name:"js", type:"dir" },{ name:"css", type:"dir" },{ name:"img", type:"dir" },{ name:"index.html", type:"file" }] } fs.mkdir(path.join(root,pathData.rootName),(err)=>{ if(err){ return; } pathData.data.forEach((item,index)=>{ if(item.type=="dir"){ fs.mkdirSync(path.join(root,pathData.rootName,item.name)); }else if(item.type=="file"){ fs.writeFileSync(path.join(root,pathData.rootName,item.name),index_content); } }) })
