前端攻城獅---node入門
本章節會講解node的全域性方法,模組化的原理,path模組以及fs模組。
什麼是node.js
node.js是一個基於chrome V8 引擎的JavaScript執行時。
就是說這個node.js可以用來執行js檔案,這樣我們就不需要在瀏覽器裡執行js檔案,只需在node中,大大方便了我們的開發。
首先,大家就需要去安裝好node,配置好環境變數,那麼我們就可以開始學習node之旅。
基本node全域性變數
我們先來講解node的全域性變數,當然我們不可能全部講,找些重點和常用的
- __dirname
- __filename
- 定時器
- 程序物件
- global
__dirname(前面有兩個下劃線)
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);
node模組化
為什麼我們要學習模組化?比如說有這麼一個應用場景,a.js需要呼叫b.js的方法?那麼我們需要如何去應用b.js的方法呢?這時候我們就是用將b.js模組化。
匯出模組有兩種方式
- exports.xxx=xxx
- module.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指向的是兩個物件,所以在呼叫的時候會找不到該方法。
path模組
通過線面模板的匯出有了一些認識之後,我們來學習一下node給我們的path模組。
如何引入模組?
var path = require("path"); ------所有node的模組引入都是 require(xxx);
path模組是幹什麼的呢?主要是用來操作路徑的
- basename
- dirname
- extname
- format
- parse
- isAbsolute
- join
- normalize
- relative
- resolve
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模組
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);
}
})
})