zoukankan      html  css  js  c++  java
  • 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 ');
    });
     
    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 ');
    });
     
    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 ');
    });
     
    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 ');
    });

    上述示例代码中,我们可以知道,通过 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 ');
    });

    所以,箭头函数的主要用法之一,就是用来简化回调函数的使用。

    模板字符串

    在 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
  • 相关阅读:
    业务逻辑安全之登陆认证模块
    linux下的tcpdump
    wirshark使用(二)
    wirshark 使用(一)
    MVC框架的代码审计小教程
    记一次发卡网代码审计
    HTML知识点(一)
    jQuery基础、效果和事件
    Ajax知识(二)
    jQueryHTML和插件、display和overflow和visibility的区别
  • 原文地址:https://www.cnblogs.com/tanlujia/p/6394251.html
Copyright © 2011-2022 走看看