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

转载于:https://www.cnblogs.com/tanlujia/p/6394251.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值