Node.js 官方示例中的 ECMAScript 2015
Posted 龙云全栈
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Node.js 官方示例中的 ECMAScript 2015相关的知识,希望对你有一定的参考价值。
第一个 Node.js 的服务器应用
Node.js 官方提供的帮助文档中,提供了一个非常适合入门的示例代码。可以帮助我们快速了解 Node.js 的主要作用。
1. 创建 example.js 文件,并将官方帮助文档提供的代码进行粘贴:
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:
node example.js
需要注意的是:上述命令必须在命令行模式下,进入到 example.js 文件所在的目录。
命令运行成功后,在命令行窗口会看到如下效果:
3. 打开浏览器,在地址栏输入命令行窗口提供的地址,访问 Node.js 服务:
http://127.0.0.1:3000
由于所有示例代码 Node.js 官方帮助文档提供了,所以运行演示的操作步骤非常简单。但,我们不能忽略其中的一些细节。
仔细阅读上述示例代码,我们会发现其中使用了很多有关 ECMAScript 2015 规范中的新内容。那接下来,就让我们一一来了解一下吧。
const
、let
和var
的区别
首先,我们可以发现,在 Node.js 的官方帮助文档提供的示例代码中,大量地使用了 const
关键字。
const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer()
const
关键字是 ECMAScript 2015 规范中的新内容,是用来定义常量的。在 ECMAScript 2015 规范中还新增了 let
关键字,来替换原本的 var
关键字。
const
、let
和 var
关键字,都是用来在 javascript 中定义变量的。
1. 关于 JavaScript 的变量
变量是具有名字存储数据信息的容器。在代码中,使用变量名为值命名,需要遵守一定的规则。
值得注意的是:
- 在 JavaScript 代码中,必须先声明一个变量,这个变量才能被使用。
- JavaScript 中的变量是弱类型的,也称之为松散类型的。所谓弱类型/松散类型就是可以用来保存任何类型的数据。
var v = 100;
v = "string";
2. 变量的声明问题
1)重复声明
使用 var
关键字重复声明变量是合法且无害的。但是如果重复声明并初始化的,这就表示重复声明并初始化。由于 JavaScript 变量只能存储一个数据,之前存储的数据会被覆盖。
var msg = "this is message";// 值为 this is message
var msg = 100;// 值为 100
2)遗漏声明
- 直接读取一个没有声明的变量的值,JavaScript 会报错。
console.log(str);
上述示例代码,直接读取了一个名为 str 的变量,但该变量并没有声明。所以,JavaScript 会报如下错误:
ReferenceError: str is not defined
- 为一个没有声明的变量初始化,是合法的,但并不推荐这样使用。
3)声明提前
JavaScript 变量的另一特别之处是,你可以引用稍后声明的变量,而不会引发异常。这一概念称为变量声明提升。
console.log( msg );// 不会报错,输出 undefined
var msg = "this is message";// 定义全局变量 msg
console.log( msg );// 输出 this is message
上述代码中的第一行输出不会报错,而是输出 undefined值。效果等同于如下述代码:
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 只存在全局作用域和函数作用域。
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);
上述示例代码,运行时会报如下错误:
v1 in function scope: this is global variable
v2 in function scope: this is function variable
v1 in global scope: this is global variable
scope.js:13
console.log('v2in global scope: '+v2);
^
ReferenceError: v2 is not defined
上述报错的原因在于 v2
变量是被定义在 fn
函数中,是局部变量,并不能在全局作用域被调用。
接下来,我们再看另外一个示例:
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
,会有什么变化呢?
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);
上述修改过的示例代码,运行时会报如下错误:
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
关键字声明的变量,是不存在声明提前的。
console.log( msg );
let msg = "this is message";
console.log( msg );
上述示例代码,运行是回报如下错误:
ReferenceError: msg is not defined
根据上述报错信息,表示使用 let
定义变量时,必须先声明,后调用。
3) let
不允许重复声明
let
与 var
的第三个区别在于,使用 let
关键字声明的变量,是不允许重复声明的。
let msg = "this is message";
console.log( msg );
let msg = "this is msg too";
console.log(msg);
上述示例代码,运行时会报如下错误:
SyntaxError: Identifier 'msg' has already been declared
根据上述报错信息,表示使用 let
定义变量时,只允许声明一次,不能重复声明。
4. const
定义常量
const声明的变量只可以在声明时赋值,不可随意修改。
1)const
声明时必须赋值
const theFairest;
上述示例代码,运行时会报如下错误:
SyntaxError: Missing initializer in const declaration
2) const
定义的值不能改变
// 定义常量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
上述示例代码,运行时会报如下错误:
SyntaxError: Identifier 'MY_FAV' has already been declared
箭头函数
在 Node.js 的官方帮助文档提供的示例代码中,我们可以看到如下形式的函数:
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}/`);
});
上述示例中的函数形式,看起来很怪异,我们将其进行改写:
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 之前,我们定义一个无参函数是这样的:
var fn = function(){
return 'this is function';
}
而在 ECMAScript 2015 之后,我们可以利用箭头函数定义是这样的:
var fn = () => 'this is function';
上述两个函数的定义是等价的。
2. 定义带参的箭头函数
如果想要定义带有参数的箭头函数,可以如下方式:
var fn = v => v;
上述代码等同于如下:
var fn = function(v){
return v;
}
如果定义带有多个参数的箭头函数,可以将参数通过圆括号进行包裹。
var sum = (num1, num2) => num1 + num2;
上述代码等同于如下:
var sum = function(num1, num2) {
return num1 + num2;
}
3. 箭头函数体包含多条语句
上述示例代码中,我们只在箭头函数中定义了一条语句。那想要定义多条语句的话,可以将所有函数体内的语句通过大括号进行包裹。
var sum = (num1, num2) => {
if(num1 < num2){
return num1;
}else{
return num2;
}
}
上述代码等同于如下:
var sum = function(num1, num2) {
if(num1 < num2){
return num1;
}else{
return num2;
}
}
大括号会被解析为代码块。如果箭头函数想要返回的是复杂数据(例如对象),需要使用圆括号进行包裹。
var me = () => ({ name: "longestory" });
上述代码等同于如下:
var me = function() {
return { name: "longestory" };
}
4. 箭头函数的作用
通过上述内容,我们已经基本掌握了箭头函数的用法。那箭头函数究竟会有什么作用呢?我们再回过头来看看 Node.js 官方帮助文档的示例代码。
// ECMAScript 5 中的写法
http.createServer(function(req, res){
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World\n');
});
上述示例代码中,我们可以知道,通过 http
对象调用了 createServer
方法的同时向该方法传递了一个回调函数。
// ECMAScript 2015 中的写法
http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World\n');
});
所以,箭头函数的主要用法之一,就是用来简化回调函数的使用。
模板字符串
在 Node.js 的官方帮助文档提供的示例代码中,我们还看到一行比较特殊的代码。
console.log(`Server running at http://${hostname}:${port}/`);
上述示例代码如果被改写成这样,相信你会更熟悉。
console.log('Server running at http://'+hostname+':'+port+'/');
实际上,在上述代码中,其实是使用了 JavaScript 的字符串拼串。而 Node.js 的官方帮助文档中的示例代码,则使用 ECMAScript 2015 规范中的 模板字符串。
1. 模板字符串的基本使用
模板字符串(template string)是增强版的字符串,用反引号(`)标识。
console.log(`this is a string.`);
上述示例代码的输出结果如下:
this is a string.
你会发现上述示例代码的输出结果与 ECMAScript 5 中的普通字符串并没有任何区别。
console.log('this is a string.');
但,如果我们想要输出的字符串很复杂,或者是多行的。那 ECMAScript 5 中的写法应该是这样的:
$('#list').html(
'<ul>'+
'<li>first</li>'+
'<li>second</li>'+
'</ul>';
);
而使用 ECMAScript 2015 规范中的模板字符串,我们就可以写成这样:
$('#list').html(`
<ul>
<li>first</li>
<li>second</li>
</ul>
`);
2. 模板字符串中使用变量
如果输出的是一些文本加上变量的内容的话,在 ECMAScript 5 中的写法是这样的:
const hostname = '127.0.0.1';
const port = 3000;
console.log('Server running at http://'+hostname+':'+port+'/');
也就是说,我们在实际开发中,需要大量的字符串拼写工作。这样做的问题在于:
- 工作量巨大
- 比较容易出错
而 ECMAScript 2015 规范中的模板字符串,则允许嵌入变量。只需要将需要嵌入的变量通过 ${}
进行包裹即可。
const hostname = '127.0.0.1';
const port = 3000;
console.log(`Server running at http://${hostname}:${port}/`);
在模板字符串中,甚至可以嵌入函数的调用。
function fn(){
return 'Hello';
}
console.log(`${fn()} World`);
上述示例代码运行的结果如下:
Hello World
3. 模板字符串的注意事项
当然,模板字符串在使用过程中,也需要注意一些问题。
如果模板字符串中嵌入的变量没有声明,则会报错。
console.log(`Server running at http://${hostname}/`);
上述示例代码,运行后会报如下错误:
ReferenceError: hostname is not defined
以上是关于Node.js 官方示例中的 ECMAScript 2015的主要内容,如果未能解决你的问题,请参考以下文章
Node.js 0.12 中提供的 ECMAScript 6 功能
Node.js 宣布正式支持 ECMAScript modules