nodejs-入門教程

一、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"
    }
最后編輯于
?著作權(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ù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容