Node.js 官方示例中的 ECMAScript 2015


第一個 Node.js 的服務器應用

Node.js 官方提供的幫助文檔中,提供了一個非常適合入門的示例代碼。可以幫助我們快速了解 Node.js 的主要作用。

1. 創建 example.js 文件,並將官方幫助文檔提供的代碼進行粘貼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const http = require('http');
 
const hostname = '127.0.0.1';
const port = 3000;
 
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader( 'Content-Type', 'text/plain');
res.end( 'Hello World\n');
});
 
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
2. 打開命令行窗口,輸入如下 node 命令,運行 example.js:
1
node example.js

需要注意的是:上述命令必須在命令行模式下,進入到 example.js 文件所在的目錄。

命令運行成功后,在命令行窗口會看到如下效果:

3. 打開瀏覽器,在地址欄輸入命令行窗口提供的地址,訪問 Node.js 服務:
1
http://127.0.0.1:3000

由於所有示例代碼 Node.js 官方幫助文檔提供了,所以運行演示的操作步驟非常簡單。但,我們不能忽略其中的一些細節。

仔細閱讀上述示例代碼,我們會發現其中使用了很多有關 ECMAScript 2015 規范中的新內容。那接下來,就讓我們一一來了解一下吧。

constlet 和 var 的區別

首先,我們可以發現,在 Node.js 的官方幫助文檔提供的示例代碼中,大量地使用了 const 關鍵字。

1
2
3
4
5
6
const http = require('http');
 
const hostname = '127.0.0.1';
const port = 3000;
 
const server = http.createServer()

const 關鍵字是 ECMAScript 2015 規范中的新內容,是用來定義常量的。在 ECMAScript 2015 規范中還新增了 let 關鍵字,來替換原本的 var 關鍵字。

constlet 和 var 關鍵字,都是用來在 JavaScript 中定義變量的。

1. 關於 JavaScript 的變量

變量是具有名字存儲數據信息的容器。在代碼中,使用變量名為值命名,需要遵守一定的規則。

值得注意的是:

  • 在 JavaScript 代碼中,必須先聲明一個變量,這個變量才能被使用。
  • JavaScript 中的變量是弱類型的,也稱之為松散類型的。所謂弱類型/松散類型就是可以用來保存任何類型的數據。
1
2
var v = 100;
v = "string";

2. 變量的聲明問題

1)重復聲明

使用 var 關鍵字重復聲明變量是合法且無害的。但是如果重復聲明並初始化的,這就表示重復聲明並初始化。由於 JavaScript 變量只能存儲一個數據,之前存儲的數據會被覆蓋。

1
2
var msg = "this is message";// 值為 this is message
var msg = 100;// 值為 100
2)遺漏聲明
  • 直接讀取一個沒有聲明的變量的值,JavaScript 會報錯。
1
console.log(str);

上述示例代碼,直接讀取了一個名為 str 的變量,但該變量並沒有聲明。所以,JavaScript 會報如下錯誤:

1
ReferenceError: str is not defined
  • 為一個沒有聲明的變量初始化,是合法的,但並不推薦這樣使用。
3)聲明提前

JavaScript 變量的另一特別之處是,你可以引用稍后聲明的變量,而不會引發異常。這一概念稱為變量聲明提升。

1
2
3
console.log( msg );// 不會報錯,輸出 undefined
var msg = "this is message";// 定義全局變量 msg
console.log( msg );// 輸出 this is message

上述代碼中的第一行輸出不會報錯,而是輸出 undefined值。效果等同於如下述代碼:

1
2
3
4
var msg;// 定義全局變量 msg,但未初始化
console.log( msg );// 不會報錯,輸出 undefined
msg = "this is message";// 初始化全局變量 msg
console.log( msg );// 輸出 this is message
3. let 是更完美的 var
1)let 擁有塊級作用域

在 ECMAScript 2015 規范發布之前,JavaScript 只存在全局作用域和函數作用域。

1
2
3
4
5
6
7
8
9
10
11
12
13
var v1 = 'this is global variable';
 
function fn(){
var v2 = 'this is function variable';
 
console.log('v1 in function scope: '+v1);
console.log('v2 in function scope: '+v2);
}
 
fn(); // 在函數作用域中調用全局變量和局部變量
// 在全局作用域中調用全局變量和局部變量
console.log('v1 in global scope: '+v1);
console.log('v2 in global scope: '+v2);

上述示例代碼,運行時會報如下錯誤:

1
2
3
4
5
6
7
8
v1in function scope: this is global variable
v2in function scope: this is function variable
v1in global scope: this is global variable
 
scope.js:13
console.log('v2in global scope: '+v2);
^
ReferenceError: v2 is not defined

上述報錯的原因在於 v2 變量是被定義在 fn 函數中,是局部變量,並不能在全局作用域被調用。

接下來,我們再看另外一個示例:

1
2
3
4
for(var i=0;i<=9;i++){
console.log('use var define variable i in function scope: '+i);
}
console.log('use var define variable i in global scope: '+i);

上述示例代碼的運行結果如下:

上述結果表明,在 for 循環語句中定義的 i 變量是一個全局變量,因為在 ECMAScript 2015 之前,JavaScript 並不存在塊級作用域。

而將上述示例代碼中,定義 i 變量的關鍵字 var 改成 let,會有什么變化呢?

1
2
3
4
for(let i=0;i<=9;i++){
console.log('use var define variable i in function scope: '+i);
}
console.log('use var define variable i in global scope: '+i);

上述修改過的示例代碼,運行時會報如下錯誤:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
use var define variable i in function scope: 0
use var define variable i in function scope: 1
use var define variable i in function scope: 2
use var define variable i in function scope: 3
use var define variable i in function scope: 4
use var define variable i in function scope: 5
use var define variable i in function scope: 6
use var define variable i in function scope: 7
use var define variable i in function scope: 8
use var define variable i in function scope: 9
/Users/king/node_and_mongoDB_in_action/01_first_node_demo/block_scope.js:10
console.log('use var define variable i in global scope: '+i);
^
ReferenceError: i is not defined

根據上述報錯信息,我們可以知道在 for 循環外打印的 i 變量未定義。換句話講,就說明 i 變量只作用於 for 循環語句內部,而不是全局作用域。

像上述示例中的 i 變量的作用域,我們就可以稱之為 塊級作用域

2)let 不存在聲明提前

let 與 var 的第二個區別在於,使用 let 關鍵字聲明的變量,是不存在聲明提前的。

1
2
3
console.log( msg );
let msg = "this is message";
console.log( msg );

上述示例代碼,運行是回報如下錯誤:

1
ReferenceError: msg is not defined

根據上述報錯信息,表示使用 let 定義變量時,必須先聲明,后調用。

3) let 不允許重復聲明

let 與 var 的第三個區別在於,使用 let 關鍵字聲明的變量,是不允許重復聲明的。

1
2
3
4
let msg = "this is message";
console.log( msg );
let msg = "this is msg too";
console.log(msg);

上述示例代碼,運行時會報如下錯誤:

1
SyntaxError: Identifier 'msg' has already been declared

根據上述報錯信息,表示使用 let 定義變量時,只允許聲明一次,不能重復聲明。

4. const 定義常量

const聲明的變量只可以在聲明時賦值,不可隨意修改。

1)const 聲明時必須賦值
1
const theFairest;

上述示例代碼,運行時會報如下錯誤:

1
SyntaxError: Missing initializer in const declaration
2) const 定義的值不能改變
1
2
3
4
5
6
7
8
9
// 定義常量MY_FAV並賦值7
const MY_FAV = 7;
 
// 在 Firefox 和 Chrome 這會失敗但不會報錯(在 Safari這個賦值會成功)
MY_FAV = 20;
console.log(MY_FAV); // 輸出 7
const MY_FAV = 20; // 嘗試重新聲明會報錯
var MY_FAV = 20;// MY_FAV 保留給上面的常量,這個操作會失敗
console.log(MY_FAV);// MY_FAV 依舊為7

上述示例代碼,運行時會報如下錯誤:

1
SyntaxError: Identifier 'MY_FAV' has already been declared

箭頭函數

在 Node.js 的官方幫助文檔提供的示例代碼中,我們可以看到如下形式的函數:

1
2
3
4
5
6
7
8
9
http.createServer( (req, res) => {
res.statusCode = 200;
res.setHeader( 'Content-Type', 'text/plain');
res.end( 'Hello World\n');
});
 
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});

上述示例中的函數形式,看起來很怪異,我們將其進行改寫:

1
2
3
4
5
6
7
8
9
const server = http.createServer(function(req, res){
res.statusCode = 200;
res.setHeader( 'Content-Type', 'text/plain');
res.end( 'Hello World\n');
});
 
server.listen(port, hostname, function(){
console.log(`Server running at http://${hostname}:${port}/`);
});

進行改寫后的代碼,是否更熟悉一些呢。那 Node.js 官方幫助文檔中提供的示例代碼里使用的又是什么呢?

1. 定義無參的箭頭函數

在 ECMAScript 5 之前,我們定義一個無參函數是這樣的:

1
2
3
var fn = function(){
return 'this is function';
}

而在 ECMAScript 2015 之后,我們可以利用箭頭函數定義是這樣的:

1
var fn = () => 'this is function';

上述兩個函數的定義是等價的。

2. 定義帶參的箭頭函數

如果想要定義帶有參數的箭頭函數,可以如下方式:

1
var fn = v => v;

上述代碼等同於如下:

1
2
3
var fn = function(v){
return v;
}

如果定義帶有多個參數的箭頭函數,可以將參數通過圓括號進行包裹。

1
var sum = (num1, num2) => num1 + num2;

上述代碼等同於如下:

1
2
3
var sum = function(num1, num2) {
return num1 + num2;
}

3. 箭頭函數體包含多條語句

上述示例代碼中,我們只在箭頭函數中定義了一條語句。那想要定義多條語句的話,可以將所有函數體內的語句通過大括號進行包裹。

1
2
3
4
5
6
7
var sum = (num1, num2) => {
if(num1 < num2){
return num1;
} else{
return num2;
}
}

上述代碼等同於如下:

1
2
3
4
5
6
7
var sum = function(num1, num2) {
if(num1 < num2){
return num1;
} else{
return num2;
}
}

大括號會被解析為代碼塊。如果箭頭函數想要返回的是復雜數據(例如對象),需要使用圓括號進行包裹。

1
var me = () => ({ name: "longestory" });

上述代碼等同於如下:

1
2
3
var me = function() {
return { name: "longestory" };
}

4. 箭頭函數的作用

通過上述內容,我們已經基本掌握了箭頭函數的用法。那箭頭函數究竟會有什么作用呢?我們再回過頭來看看 Node.js 官方幫助文檔的示例代碼。

1
2
3
4
5
6
// ECMAScript 5 中的寫法
http.createServer( function(req, res){
res.statusCode = 200;
res.setHeader( 'Content-Type', 'text/plain');
res.end( 'Hello World\n');
});

上述示例代碼中,我們可以知道,通過 http 對象調用了 createServer 方法的同時向該方法傳遞了一個回調函數。

1
2
3
4
5
6
// ECMAScript 2015 中的寫法
http.createServer( (req, res) => {
res.statusCode = 200;
res.setHeader( 'Content-Type', 'text/plain');
res.end( 'Hello World\n');
});

所以,箭頭函數的主要用法之一,就是用來簡化回調函數的使用。

模板字符串

在 Node.js 的官方幫助文檔提供的示例代碼中,我們還看到一行比較特殊的代碼。

1
console.log(`Server running at http://${hostname}:${port}/`);

上述示例代碼如果被改寫成這樣,相信你會更熟悉。

1
console.log('Server running at http://'+hostname+':'+port+'/');

實際上,在上述代碼中,其實是使用了 JavaScript 的字符串拼串。而 Node.js 的官方幫助文檔中的示例代碼,則使用 ECMAScript 2015 規范中的 模板字符串

1. 模板字符串的基本使用

模板字符串(template string)是增強版的字符串,用反引號(`)標識。

1
console.log(`this is a string.`);

上述示例代碼的輸出結果如下:

1
this is a string.

你會發現上述示例代碼的輸出結果與 ECMAScript 5 中的普通字符串並沒有任何區別。

1
console.log('this is a string.');

但,如果我們想要輸出的字符串很復雜,或者是多行的。那 ECMAScript 5 中的寫法應該是這樣的:

1
2
3
4
5
6
$( '#list').html(
'<ul>'+
'<li>first</li>'+
'<li>second</li>'+
'</ul>'
);

而使用 ECMAScript 2015 規范中的模板字符串,我們就可以寫成這樣:

1
2
3
4
5
6
$( '#list').html(`
<ul>
<li>first</li>
<li>second</li>
</ul>
`);

2. 模板字符串中使用變量

如果輸出的是一些文本加上變量的內容的話,在 ECMAScript 5 中的寫法是這樣的:

1
2
3
const hostname = '127.0.0.1';
const port = 3000;
console.log('Server running at http://'+hostname+':'+port+'/');

也就是說,我們在實際開發中,需要大量的字符串拼寫工作。這樣做的問題在於:

  • 工作量巨大
  • 比較容易出錯

而 ECMAScript 2015 規范中的模板字符串,則允許嵌入變量。只需要將需要嵌入的變量通過 ${} 進行包裹即可。

1
2
3
const hostname = '127.0.0.1';
const port = 3000;
console.log(`Server running at http://${hostname}:${port}/`);

在模板字符串中,甚至可以嵌入函數的調用。

1
2
3
4
function fn(){
return 'Hello';
}
console.log(`${fn()} World`);

上述示例代碼運行的結果如下:

1
Hello World

3. 模板字符串的注意事項

當然,模板字符串在使用過程中,也需要注意一些問題。

如果模板字符串中嵌入的變量沒有聲明,則會報錯。

1
console.log(`Server running at http://${hostname}/`);

上述示例代碼,運行后會報如下錯誤:

1
ReferenceError: hostname is not defined


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM