一、Node js入門
1.如果要運行一大段代碼的話,可以先寫一個JS文件再運行。例如有以下`hello.js`。
function hello() {
console.log('Hello World!');
}
hello();
寫好后在終端下鍵入`node hello.js`運行,結(jié)果如下:
$ node hello.js
Hello World!
2.#### require
`require`函數(shù)用于在當(dāng)前模塊中加載和使用別的模塊,傳入一個模塊名,返回一個模塊導(dǎo)出對象。模塊名可使用相對路徑(以`./`開頭),或者是絕對路徑(以`/`或`C:`之類的盤符開頭)。另外,模塊名中的`.js`擴(kuò)展名可以省略。以下是一個例子。
var foo1 = require('./foo');
var foo2 = require('./foo.js');
var foo3 = require('/home/user/foo');
var foo4 = require('/home/user/foo.js');
// foo1至foo4中保存的是同一個模塊的導(dǎo)出對象。
另外,可以使用以下方式加載和使用一個JSON文件。
var data = require('./data.json');
3.#### exports
`exports`對象是當(dāng)前模塊的導(dǎo)出對象,用于導(dǎo)出模塊公有方法和屬性。別的模塊通過`require`函數(shù)使用當(dāng)前模塊時得到的就是當(dāng)前模塊的`exports`對象。以下例子中導(dǎo)出了一個公有方法。
exports.hello = function () {
console.log('Hello World!');
};
4.#### module
通過`module`對象可以訪問到當(dāng)前模塊的一些相關(guān)信息,但最多的用途是替換當(dāng)前模塊的導(dǎo)出對象。例如模塊導(dǎo)出對象默認(rèn)是一個普通對象,如果想改成一個函數(shù)的話,可以使用以下方式。
module.exports = function () {
console.log('Hello World!');
};
以上代碼中,模塊默認(rèn)導(dǎo)出對象被替換為一個函數(shù)。
5.#### 完整示例
例如有以下目錄。
- /home/user/hello/
- util/
counter.js
main.js
其中`counter.js`內(nèi)容如下:
var i = 0;
function count() {
return ++i;
}
exports.count = count;
該模塊內(nèi)部定義了一個私有變量`i`,并在`exports`對象導(dǎo)出了一個公有方法`count`。
主模塊`main.js`內(nèi)容如下:
var counter1 = require('./util/counter');
var counter2 = require('./util/counter');
console.log(counter1.count());
console.log(counter2.count());
console.log(counter2.count());
運行該程序的結(jié)果如下:
$ node main.js
1
2
3
可以看到,`counter.js`并沒有因為被require了兩次而初始化兩次。
第二章、代碼組織
1.`require`函數(shù)路徑解析
`require`函數(shù)支持斜杠(`/`)或盤符(`C:`)開頭的絕對路徑,也支持`./`開頭的相對路徑。但這兩種路徑在模塊之間建立了強(qiáng)耦合關(guān)系,一旦某個模塊文件的存放位置需要變更,使用該模塊的其它模塊的代碼也需要跟著調(diào)整,變得牽一發(fā)動全身。因此,`require`函數(shù)支持第三種形式的路徑,寫法類似于`foo/bar`,并依次按照以下規(guī)則解析路徑,直到找到模塊位置。
(1)內(nèi)置模塊
如果傳遞給`require`函數(shù)的是NodeJS內(nèi)置模塊名稱,不做路徑解析,直接返回內(nèi)部模塊的導(dǎo)出對象,例如`require('fs')`。
(2)node_modules目錄
NodeJS定義了一個特殊的`node_modules`目錄用于存放模塊。例如某個模塊的絕對路徑是`/home/user/hello.js`,在該模塊中使用`require('foo/bar')`方式加載模塊時,則NodeJS依次嘗試使用以下路徑。
/home/user/node_modules/foo/bar
/home/node_modules/foo/bar
/node_modules/foo/bar
(3) NODE_PATH環(huán)境變量
與PATH環(huán)境變量類似,NodeJS允許通過NODE_PATH環(huán)境變量來指定額外的模塊搜索路徑。NODE_PATH環(huán)境變量中包含一到多個目錄路徑,路徑之間在Linux下使用`:`分隔,在Windows下使用`;`分隔。例如定義了以下NODE_PATH環(huán)境變量:
NODE_PATH=/home/user/lib:/home/lib
當(dāng)使用`require('foo/bar')`的方式加載模塊時,則NodeJS依次嘗試以下路徑。
/home/user/lib/foo/bar
/home/lib/foo/bar
2.包管理——便于管理和使用,由多個子模塊組成
在組成一個包的所有子模塊中,需要有一個入口模塊,入口模塊的導(dǎo)出對象被作為包的導(dǎo)出對象。例如有以下目錄結(jié)構(gòu)。
- /home/user/lib/
- cat/
head.js
body.js
main.js
其中`cat`目錄定義了一個包,其中包含了3個子模塊。`main.js`作為入口模塊,其內(nèi)容如下:
var head = require('./head');
var body = require('./body');
exports.create = function (name) {
return {
name: name,
head: head.create(),
body: body.create()
};
};
在其它模塊里使用包的時候,需要加載包的入口模塊。接著上例,使用`require('/home/user/lib/cat/main')`能達(dá)到目的,但是入口模塊名稱出現(xiàn)在路徑里看上去不是個好主意。因此我們需要做點額外的工作,讓包使用起來更像是單個模塊。
(1)#### index.js
當(dāng)模塊的文件名是`index.js`,加載模塊時可以使用模塊所在目錄的路徑代替模塊文件路徑,因此接著上例,以下兩條語句等價。
var cat = require('/home/user/lib/cat');
var cat = require('/home/user/lib/cat/index');
這樣處理后,就只需要把包目錄路徑傳遞給`require`函數(shù),感覺上整個目錄被當(dāng)作單個模塊使用,更有整體感。
(2)#### package.json
如果想自定義入口模塊的文件名和存放位置,就需要在包目錄下包含一個`package.json`文件,并在其中指定入口模塊的路徑。上例中的`cat`模塊可以重構(gòu)如下。
- /home/user/lib/
- cat/
+ doc/
- lib/
head.js
body.js
main.js
+ tests/
package.json
其中`package.json`內(nèi)容如下。
{
"name": "cat",
"main": "./lib/main.js"
}
如此一來,就同樣可以使用`require('/home/user/lib/cat')`的方式加載模塊。NodeJS會根據(jù)包目錄下的`package.json`找到入口模塊所在位置。
3.命令行執(zhí)行代碼
這種使用方式看起來不怎么像是一個命令行程序,下邊的才是我們期望的方式。
$ node-echo Hello World
#### Linux
在Linux系統(tǒng)下,我們可以把JS文件當(dāng)作shell腳本來運行,從而達(dá)到上述目的,具體步驟如下:
(1) 在shell腳本中,可以通過`#!`注釋來指定當(dāng)前腳本使用的解析器。所以我們首先在`node-echo.js`文件頂部增加以下一行注釋,表明當(dāng)前腳本使用NodeJS解析。
#! /usr/bin/env node
NodeJS會忽略掉位于JS模塊首行的`#!`注釋,不必?fù)?dān)心這行注釋是非法語句。
(2) 然后,我們使用以下命令賦予`node-echo.js`文件執(zhí)行權(quán)限。
$ chmod +x /home/user/bin/node-echo.js
(3)最后,我們在PATH環(huán)境變量中指定的某個目錄下,例如在`/usr/local/bin`下邊創(chuàng)建一個軟鏈文件,文件名與我們希望使用的終端命令同名,命令如下:
$ sudo ln -s /home/user/bin/node-echo.js /usr/local/bin/node-echo
這樣處理后,我們就可以在任何目錄下使用`node-echo`命令了。
#### Windows
在Windows系統(tǒng)下的做法完全不同,我們得靠`.cmd`文件來解決問題。假設(shè)`node-echo.js`存放在`C:\Users\user\bin`目錄,并且該目錄已經(jīng)添加到PATH環(huán)境變量里了。接下來需要在該目錄下新建一個名為`node-echo.cmd`的文件,文件內(nèi)容如下:
@node "C:\User\user\bin\node-echo.js" %*
這樣處理后,我們就可以在任何目錄下使用`node-echo`命令了。
4.工程目錄
了解了以上知識后,現(xiàn)在我們可以來完整地規(guī)劃一個工程目錄了。以編寫一個命令行程序為例,一般我們會同時提供命令行模式和API模式兩種使用方式,并且我們會借助三方包來編寫代碼。除了代碼外,一個完整的程序也應(yīng)該有自己的文檔和測試用例。因此,一個標(biāo)準(zhǔn)的工程目錄都看起來像下邊這樣。
- /home/user/workspace/node-echo/ # 工程目錄
- bin/ # 存放命令行相關(guān)代碼
node-echo
+ doc/ # 存放文檔
- lib/ # 存放API相關(guān)代碼
echo.js
- node_modules/ # 存放三方包
+ argv/
+ tests/ # 存放測試用例
package.json # 元數(shù)據(jù)文件
README.md # 說明文件
其中部分文件內(nèi)容如下:
/* bin/node-echo */
var argv = require('argv'),
echo = require('../lib/echo');
console.log(echo(argv.join(' ')));
/* lib/echo.js */
module.exports = function (message) {
return message;
};
/* package.json */
{
"name": "node-echo",
"main": "./lib/echo.js"
}
以上例子中分類存放了不同類型的文件,并通過`node_moudles`目錄直接使用三方包名加載模塊。此外,定義了`package.json`之后,`node-echo`目錄也可被當(dāng)作一個包來使用。
5、NPM使用
### NPM
NPM是隨同NodeJS一起安裝的包管理工具,能解決NodeJS代碼部署上的很多問題,常見的使用場景有以下幾種:
+ 允許用戶從NPM服務(wù)器下載別人編寫的三方包到本地使用。
+ 允許用戶從NPM服務(wù)器下載并安裝別人編寫的命令行程序到本地使用。
+ 允許用戶將自己編寫的包或命令行程序上傳到NPM服務(wù)器供別人使用。
可以看到,NPM建立了一個NodeJS生態(tài)圈,NodeJS開發(fā)者和用戶可以在里邊互通有無。以下分別介紹這三種場景下怎樣使用NPM。
#### 下載三方包
需要使用三方包時,首先得知道有哪些包可用。雖然[npmjs.org](https://npmjs.org/)提供了個搜索框可以根據(jù)包名來搜索,但如果連想使用的三方包的名字都不確定的話,就請百度一下吧。知道了包名后,比如上邊例子中的`argv`,就可以在工程目錄下打開終端,使用以下命令來下載三方包。
$ npm install argv
...
argv@0.0.2 node_modules\argv
下載好之后,`argv`包就放在了工程目錄下的`node_modules`目錄中,因此在代碼中只需要通過`require('argv')`的方式就好,無需指定三方包路徑。
以上命令默認(rèn)下載最新版三方包,如果想要下載指定版本的話,可以在包名后邊加上`@<version>`,例如通過以下命令可下載0.0.1版的`argv`。
$ npm install argv@0.0.1
...
argv@0.0.1 node_modules\argv
如果使用到的三方包比較多,在終端下一個包一條命令地安裝未免太人肉了。因此NPM對`package.json`的字段做了擴(kuò)展,允許在其中申明三方包依賴。因此,上邊例子中的`package.json`可以改寫如下:
{
"name": "node-echo",
"main": "./lib/echo.js",
"dependencies": {
"argv": "0.0.2"
}
}
這樣處理后,在工程目錄下就可以使用`npm install`命令批量安裝三方包了。更重要的是,當(dāng)以后`node-echo`也上傳到了NPM服務(wù)器,別人下載這個包時,NPM會根據(jù)包中申明的三方包依賴自動下載進(jìn)一步依賴的三方包。例如,使用`npm install node-echo`命令時,NPM會自動創(chuàng)建以下目錄結(jié)構(gòu)。
- project/
- node_modules/
- node-echo/
- node_modules/
+ argv/
...
...
如此一來,用戶只需關(guān)心自己直接使用的三方包,不需要自己去解決所有包的依賴關(guān)系。
#### 安裝命令行程序
從NPM服務(wù)上下載安裝一個命令行程序的方法與三方包類似。例如上例中的`node-echo`提供了命令行使用方式,只要`node-echo`自己配置好了相關(guān)的`package.json`字段,對于用戶而言,只需要使用以下命令安裝程序。
$ npm install node-echo -g
參數(shù)中的`-g`表示全局安裝,因此`node-echo`會默認(rèn)安裝到以下位置,并且NPM會自動創(chuàng)建好Linux系統(tǒng)下需要的軟鏈文件或Windows系統(tǒng)下需要的`.cmd`文件。
- /usr/local/ # Linux系統(tǒng)下
- lib/node_modules/
+ node-echo/
...
- bin/
node-echo
...
...
- %APPDATA%\npm\ # Windows系統(tǒng)下
- node_modules\
+ node-echo\
...
node-echo.cmd
...
#### 發(fā)布代碼
第一次使用NPM發(fā)布代碼前需要注冊一個賬號。終端下運行`npm adduser`,之后按照提示做即可。賬號搞定后,接著我們需要編輯`package.json`文件,加入NPM必需的字段。接著上邊`node-echo`的例子,`package.json`里必要的字段如下。
{
"name": "node-echo", # 包名,在NPM服務(wù)器上須要保持唯一
"version": "1.0.0", # 當(dāng)前版本號
"dependencies": { # 三方包依賴,需要指定包名和版本號
"argv": "0.0.2"
},
"main": "./lib/echo.js", # 入口模塊位置
"bin" : {
"node-echo": "./bin/node-echo" # 命令行程序名和主模塊位置
}
}
之后,我們就可以在`package.json`所在目錄下運行`npm publish`發(fā)布代碼了
1.express入門
var express =require('express');
var app=express();
//demo121
app.get('/demo:id',function(req,res){
//console.log(__dirname);
res.send('hello world1dddd!!'+req.params['id']);
console.log(req.cookies);
});
//app.use('/static', express.static(__dirname + '/public'));
app.use(express.static( 'public'));
// 一個簡單的 logger
app.use(function(req, res, next){
console.log('%s %s', req.method, req.url);
next();
});
var server=app.listen(3000,function(){
var host=server.address().address;
var port=server.address().port;
});
2.開始
var http=require('http');
http.createServer(function(req,res){
res.writeHead(200,{'Content-Type':'text/plain'});
res.end('<h1>Hello World</h1>\n');
}).listen(80,'127.0.0.1');
2.定義模塊
//模塊的定義./public/js/circle.js
var PI=Math.PI;
exports.area=function(r){
return r*r*PI;
}
exports.circlePreference=function(r){
return 2*PI*r;
}
//使用
var http=require('http');
var circle=require('./public/js/circle.js');
http.createServer(function(req,res){
res.writeHead(200,{'Content-Type':'text/plain'});
res.end('<h1>Hello World</h1>\n'+circle.area(2));
}).listen(80,'127.0.0.1');
3.###`exports`
`exports`對象是當(dāng)前模塊的導(dǎo)出對象,用于導(dǎo)出模塊公有方法和屬性。別的模塊通過`require`函數(shù)使用當(dāng)前模塊時得到的就是當(dāng)前模塊的`exports`對象。以下例子中導(dǎo)出了一個公有方法。
exports.hello = function () {
console.log('Hello World!');
};
4.#### module
通過`module`對象可以訪問到當(dāng)前模塊的一些相關(guān)信息,但最多的用途是替換當(dāng)前模塊的導(dǎo)出對象。例如模塊導(dǎo)出對象默認(rèn)是一個普通對象,如果想改成一個函數(shù)的話,可以使用以下方式。
module.exports = function () {
console.log('Hello World!');
};
以上代碼中,模塊默認(rèn)導(dǎo)出對象被替換為一個函數(shù)。
5.### 模塊路徑解析規(guī)則
我們已經(jīng)知道,`require`函數(shù)支持斜杠(`/`)或盤符(`C:`)開頭的絕對路徑,也支持`./`開頭的相對路徑。但這兩種路徑在模塊之間建立了強(qiáng)耦合關(guān)系,一旦某個模塊文件的存放位置需要變更,使用該模塊的其它模塊的代碼也需要跟著調(diào)整,變得牽一發(fā)動全身。因此,`require`函數(shù)支持第三種形式的路徑,寫法類似于`foo/bar`,并依次按照以下規(guī)則解析路徑,直到找到模塊位置。
(1) 內(nèi)置模塊
如果傳遞給`require`函數(shù)的是NodeJS內(nèi)置模塊名稱,不做路徑解析,直接返回內(nèi)部模塊的導(dǎo)出對象,例如`require('fs')`。
(2) node_modules目錄
NodeJS定義了一個特殊的`node_modules`目錄用于存放模塊。例如某個模塊的絕對路徑是`/home/user/hello.js`,在該模塊中使用`require('foo/bar')`方式加載模塊時,則NodeJS依次嘗試使用以下路徑。
/home/user/node_modules/foo/bar
/home/node_modules/foo/bar
/node_modules/foo/bar
(3) NODE_PATH環(huán)境變量
與PATH環(huán)境變量類似,NodeJS允許通過NODE_PATH環(huán)境變量來指定額外的模塊搜索路徑。NODE_PATH環(huán)境變量中包含一到多個目錄路徑,路徑之間在Linux下使用`:`分隔,在Windows下使用`;`分隔。例如定義了以下NODE_PATH環(huán)境變量:
NODE_PATH=/home/user/lib:/home/lib
當(dāng)使用`require('foo/bar')`的方式加載模塊時,則NodeJS依次嘗試以下路徑。
/home/user/lib/foo/bar
/home/lib/foo/bar
6.#### index.js
當(dāng)模塊的文件名是`index.js`,加載模塊時可以使用模塊所在目錄的路徑代替模塊文件路徑,因此接著上例,以下兩條語句等價。
var cat = require('/home/user/lib/cat');
var cat = require('/home/user/lib/cat/index');
這樣處理后,就只需要把包目錄路徑傳遞給`require`函數(shù),感覺上整個目錄被當(dāng)作單個模塊使用,更有整體感。
7.#### package.json
如果想自定義入口模塊的文件名和存放位置,就需要在包目錄下包含一個`package.json`文件,并在其中指定入口模塊的路徑。上例中的`cat`模塊可以重構(gòu)如下。
- /home/user/lib/
- cat/
+ doc/
- lib/
head.js
body.js
main.js
+ tests/
package.json
其中`package.json`內(nèi)容如下。
{
"name": "cat",
"main": "./lib/main.js"
}
如此一來,就同樣可以使用`require('/home/user/lib/cat')`的方式加載模塊。NodeJS會根據(jù)包目錄下的`package.json`找到入口模塊所在位置。
8.### 工程目錄
了解了以上知識后,現(xiàn)在我們可以來完整地規(guī)劃一個工程目錄了。以編寫一個命令行程序為例,一般我們會同時提供命令行模式和API模式兩種使用方式,并且我們會借助三方包來編寫代碼。除了代碼外,一個完整的程序也應(yīng)該有自己的文檔和測試用例。因此,一個標(biāo)準(zhǔn)的工程目錄都看起來像下邊這樣。
- /home/user/workspace/node-echo/ # 工程目錄
- bin/ # 存放命令行相關(guān)代碼
node-echo
+ doc/ # 存放文檔
- lib/ # 存放API相關(guān)代碼
echo.js
- node_modules/ # 存放三方包
+ argv/
+ tests/ # 存放測試用例
package.json # 元數(shù)據(jù)文件
README.md # 說明文件
其中部分文件內(nèi)容如下:
/* bin/node-echo */
var argv = require('argv'),
echo = require('../lib/echo');
console.log(echo(argv.join(' ')));
/* lib/echo.js */
module.exports = function (message) {
return message;
};
/* package.json */
{
"name": "node-echo",
"main": "./lib/echo.js"
}
nodejs-入門教程
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
相關(guān)閱讀更多精彩內(nèi)容
- JavaScript與Node.js JavaScript與你 拋開技術(shù),我們先來聊聊你以及你和JavaScrip...
- 1.錯誤:Express Command not found 最初操作:跟著《nodejs開發(fā)指南》敲npm in...
- 既然nodejs各處都體現(xiàn)到模塊,那么這里就將數(shù)據(jù)庫操作獨立成一個單獨的模塊,之后按需加載。 在當(dāng)前項目目錄下新建...
- 一、簡介 pm2是一個帶有負(fù)載均衡功能的應(yīng)用進(jìn)程管理器,類似有Supervisor,forever。 二、安裝 L...