1. 程式人生 > >前端攻城獅---node入門

前端攻城獅---node入門

本章節會講解node的全域性方法,模組化的原理,path模組以及fs模組。

什麼是node.js

node.js是一個基於chrome V8 引擎的JavaScript執行時。

就是說這個node.js可以用來執行js檔案,這樣我們就不需要在瀏覽器裡執行js檔案,只需在node中,大大方便了我們的開發。

首先,大家就需要去安裝好node,配置好環境變數,那麼我們就可以開始學習node之旅。

基本node全域性變數

我們先來講解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/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);
		}
	})
})
 


本章節目標已完成,接下來會講解npm相關語法,如有表達錯的請諒解,並請提出指出,且修改錯誤,望能共同進步。