入門node.js你必須知道的那些事
最基本的一些操作和概念
用node執行一段js程式碼
-
在命令列中用cd切換到桌面
-
建立一個資料夾和並用cd命令切換到這個資料夾
mkdir nodeTest && cd nodeTest -
建立一個js檔案並寫上簡單的js程式碼
touch a.js
`var a = 10; console.log(a); console.log(a + 10);
`
-
在命令列中輸入node a.js
命令列會輸出 10 20
node引用檔案的方式
-
Node.js採用了CommonJS規範,通過require來引入一個js檔案
-
新建檔案b.js 並在檔案中引入a.js
-
touch b.js
-
require(`./a.js`)
-
-
執行b.js
-
node b.js 命令列會輸出10 20
-
node中的模組概念
-
node中一個模組就是一個js檔案,多個模組組成一個特定功能的一堆檔案叫包
-
一個js檔案可以定義它自己暴露給外部的變數(意思就是另一個檔案通過require引用它後需要怎麼使用它),node中提供共了exports和module.exports兩個變數來實現它
a.js
function func1() { console.log(`aaa`) } function func2() { console.log(`bbb`) } exports.a = func1 exports.b = func2
b.js
var a = require(`./a.js`) a.a() //會列印出aaa a.b() //會列印出bbb
c.js
//es6 模式匹配寫法 var {fun1,fun2} = require(`./a.js`)//fun1和fun2必須跟a.js中的變數名相同,這裡是固定的 fun1() //會列印出aaa fun2() //會列印出bbb
a.js
//類的寫法 function Test() { this.func1 = function() { console.log(`aaa`) } this.func2 = function() { console.log(`bbb`) } } module.exports = Hello
b.js
var Test = require(`./a.js`) var test = new Test() test.func1() test.func2()
exports 和 module.exports 的關係
exports 是module.exports的一個引用,意思就是指向同一塊記憶體地址,node中真正生效的是module.exports,修改exports本質上也是修改module.exports的值,
比如exports.a = 3,實際上module.exports.a也是等於3的
又比如exports = {},這樣exports就和module.exports的指向的物件就不一樣了,後面再怎麼修改exports也不會影響到module.exports的值,也不會影響到檔案輸出的變數
再比如module.exports={},這樣造成的效果和上面exports={}的效果是一樣的這裡表達有問題,雖然module.exports={}和exports={}都是讓exports與module.exports的引用指向不同了,但是最後的效果實際上是不一樣的,具體用法參考評論區。感謝@琪琪好笨笨 指出的錯誤
建議:如果你還傻傻分不清楚它們的區別,以後在不是必須用到module.exports的時候只用exports,如果匯出一個類這樣的必須用到module.exports就不要使用exports了,不要混在一起用就不會出錯了
node中的npm
node中預設自帶了npm,npm是一個包管理器,上面說到包就是一個個模組(js檔案)組成的一個具有特定功能的一堆js檔案,通過npm我們可以引入這些包(如果不理解,把包理解成一個個外掛也沒有錯)來輕鬆實現一些功能
安裝一個模組你只需要npm install xxx 就可以安裝了,然後在你自己的js中用var xxx = require(`./xxx`)就可以使用了
通過npm install xxx 安裝完xxx模組後,你會發現當前目錄下多了一個node_modules資料夾,開啟node_modules資料夾你會發現裡面有一個xxx資料夾。你在執行npm install xxx的時候,實際上npm也只是幫你把xxx這個包下載下來了而已,僅此而已
當你通過npm安裝了十來個或者更多的包的時候你可能自己早就不知道自己安裝了哪些包了,因為很多包依賴了其它的包(一個包用到另一個包提供的功能是非常正常的行為,就像我們在用別人包裡的功能一樣),所以npm提供了package.json這個檔案來管理包
package.json 是一個檔案,裡面可以定義很多鍵值對,其中有幾個欄位非常重要,dependencies表示上線執行時依賴的包,devDependencies表示開發時依賴的包,scripts可以定義自己的指令碼,main表示所有的包你都會通過這個檔案引入
當你在dependencies和devDependencies定義好依賴,然後在命令列中輸入npm install,npm就會幫你自動安裝好這些包;反過來你在命令列中輸入npm install xxx –save後npm就會在package.json中的dependencies自動加上xxx,如果執行的是npm install xxx –save-dev 就會在devDependencies中自動加上xxx。
而在scripts中定義的指令碼就直接可以在命令列中執行了,如果還弄不懂,可以看一下我的另一篇文章,如何製作自己的npm包
node.js中自帶的那些模組
http模組
使用別人的模組,其實就是使用別人寫好的方法(函式),只需要搞清楚別人提供的方法是怎麼用的就可以了,可以查node.js官網查api或者看看網上寫的教程就好。
下面演示了一個最簡單的http模組的使用方法,在當前目錄下在命令列中輸入node test.js,http會掛起一個監聽,只需要在瀏覽器中輸入http://localhost:8000,test.js就會跟瀏覽器返回
<div>hello world</div>
顯示在頁面上:
test.js
var http = require(`http`)
var callBack = function(req, res) {
res.write(`<div>hello world</div>`)
res.end()
}
http.createServer(callBack).listen(8000)
url模組
在http模組的例子中傳入了一個回撥函式,兩個引數分別是request和response,前者是瀏覽器傳給我們的物件,後者是我們傳給瀏覽器的物件。
其中req中包含了url這個屬性,可以在回撥函式中把它列印出來
console.log(req.url)
,加入你在瀏覽器中輸入的是:http://localhost:8000/aaa/bbb?abc=3,那麼列印出來的值是:/aaa/bbb?abc=3在這裡我們需要使用到的是/aaa/bbb和abc=3分開來的結果,node給我們提供了一個處理url的模組,就叫做url模組.當然如果你自己想處理這個url也是完全可以的,用正規表示式就可以,但是已經有現成的為啥不用呢
下面簡單演示一下用法,在瀏覽器輸入:http://localhost:8000/aaa/bbb?abc=3
test.js
var http = require(`http`)
var url = require(`url`)
var callBack = function(req, res) {
var urlString = url.parse(req.url)
var path = urlString.pathname
var query = urlString.query
console.log(path,query)//列印出/aaa/bbb abc=3
res.write(`<div>hello world</div>`)
res.end()
}
http.createServer(callBack).listen(8000)
fs模組
fs是一個提供檔案操作功能的模組,可以對檔案進行讀寫存刪等操作,下面演示向瀏覽器返回本js的內容:
test.js
var http = require(`http`)
var fs = require(`fs`)
var callBack = function(req, res) {
fs.readFile(`./test.js`, `utf-8`, function(err, data) {
res.write(data)
res.end()
})
}
http.createServer(callBack).listen(8000)
用http模組、url模組、http模組搭建一個靜態伺服器
var http = require(`http`)
var url = require(`url`)
var fs = require(`fs`)
var callBack = function(req, res) {
var pathname = url.parse(req.url).pathname
if (pathname == `/`) {
pathname = `/index.html`
}
fs.readFile(`.` + pathname, `utf-8`, function(err, data) {
if (err) {
res.write(`Error 404`)
} else {
res.write(data)
}
res.end()
}
)}
http.createServer(callBack).listen(8000)
使用外部模組
簡單說明
外部模組都是第三方提供的模組,node.js預設是不提供的,所以需要用npm安裝,這裡提供package.json檔案,只需要執行npm install 安裝就行了,另外是管理MongoDB資料庫的一個包,所以本地需要把MongoDB單獨安裝一下。
package.json
{
"dependencies": {
"cheerio": "^1.0.0-rc.2",
"eventproxy": "^1.0.0",
"express": "^4.16.2",
"koa": "^2.4.1",<!--koa是用來替代express的框架-->
"superagent": "^3.8.1"
}
}
express
express提供了基本的路由和靜態檔案訪問的功能,當然還有其它的功能,這裡主要演示它的基本使用
下面1,2,3都是設定public和files目錄下為靜態檔案,可以直接通過檔案路徑訪問,1、2可以同時存在,即可以指定幾個目錄均為靜態檔案目錄,在指定目錄為靜態檔案後,訪問靜態檔案需要省略這個目錄,比如訪問public目錄下的css/index.css:localhost:8000/css/index.css,直接省略了public,
可以通過3來指定替換目錄名稱的路徑,通過3設定後,要訪問public下的css/index.css:localhost:8000/public/css/index.css
var express = require(`express`)
var app = express()
1. app.use(express.static(`public`))
2. app.use(express.static(`files`))
3. app.use(`/static`,express.static(public))
app.get(`/`, function (req, res) {
res.send(`Hello World`);//一個回撥方法對應一個路徑
})
app.get(`/user`, function (req, res) {
res.send(`user`);
})
app.listen(8000, function () {
console.log(`app is listening at port 3000`);
})
superagent、cheerio模組
superagent是一個可以發http請求的模組,回撥函式中的res就是請求到的內容
cheerio是在伺服器端類式jquery的框架,看程式碼應該能看出來
下面演示的是抓取糯米網的餐品列表連結
var superagent = require(`superagent`)
var cheerio = require(`cheerio`)
var spideUrl = `https://t10.nuomi.com/pc/t10/index`
superagent.get(spideUrl)
.end(function(err, res) {
if (err) {
return console.error(err);
}
var foodUrls = [];
var $ = cheerio.load(res.text)
// 獲取首頁所有的連結
$(`.j-item a`).each(function(idx, element) {
var $element = $(element)
foodUrls.push($element.attr(`href`))
})
console.log(topicUrls)
})
eventproxy
在爬取一堆類式的連結的時候,一個個連結寫挺麻煩的,eventproxy提供了監聽,然後觸發回撥的方式來處理這類問題,下面是我拷貝的一段程式碼,應該挺容易看懂的
//得到一個 eventproxy 的例項
var ep = new eventproxy()
// 命令 ep 重複監聽 urls.length 次(在這裡也就是 10 次)
ep.after(`topic_html`, urls.length, function (topics) {
topics = topics.map(function(page) {
var $ = cheerio.load(page)
var userId = $(`.runUserName a font`).eq(0).text()
return userId
});
console.log(topics);
})
urls.forEach(function(item) {
superagent.get(item)
.end(function (err, res) {
ep.emit(`topic_html`, res.text)
})
})
總結
大部分學習前端其實是沒必要深入學習node.js的,一方面沒那個精力,然後也沒那麼必要,但是一些基本的東西還是有必要好好學學的
大多數前端同學之所以覺得應該學前端,其實是平時接觸到的npm、require模組、es6的語法等問題覺得比較棘手,以為是自己不懂node.js,其實這些和node.js並無太大關係,這些已經影響到學習前端其它內容的地方還是需要好好學習的
學習node.js基本的東西還是有必要的,比如搭建個簡單的伺服器,做點基本的邏輯處理和資料處理,做個爬蟲啥的。而這些都很簡單,看兩篇部落格做幾個練習就夠了,再深入就根據實際情況學習就好了。