node.js是一个基于chrome V8 引擎的JavaScript运行时。
就是说这个node.js可以用来运行js文件,这样我们就不需要在浏览器里运行js文件,只需在node中,大大方便了我们的开发。
首先,大家就需要去安装好node,配置好环境变量,那么我们就可以开始学习node之旅。
node的中文官网 http://nodejs.cn/api/
我们先来讲解node的全局变量,当然我们不可能全部讲,找些重点和常用的
__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/64
global:全局变量
在node中是没有window的全局对象的,所以我们是无法使用window.alert("xxx"),在node中全局变量就是global,当然全局变量是可以省略的
global.console.log(12345);
console.log(12345);
为什么我们要学习模块化?比如说有这么一个应用场景,a.js需要调用b.js的方法?那么我们需要如何去应用b.js的方法呢?这时候我们就是用将b.js模块化。
导出模块有两种方式
两中导出方法是有差异的,并且导出方法的不同那么调用方法也是不同的
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模块是干什么的呢?主要是用来操作路径的
basename
表示获取路径的最后一个部分
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/c
extname
表示返回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.txt
isAbsolute
判断给的路径是不是绝对路径
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('.'); // false
join
表示拼接路径,路径必须是字符串
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 = `
Document
`;
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);
}
})
})