zoukankan      html  css  js  c++  java
  • ES6 常用特性总结

     回到顶部

    一、ES6 基本认识

    1、什么是 ES6?

      ES6 指的是 ECMAScript 6.0,是JavaScript 语言的一个标准。其目标是使JavaScript 可以用来编写复杂的大型的应用程序,成为企业级开发的语言。

    2、ES6 与 JavaScript 的区别?

      ES6 是 JavaScript 的一个标准,JavaScript 是 ES6 的具体实现。

    3、Babel 转码器?

      Babel 是一个被广泛使用的 ES6 转码器,其可以将 ES6 代码转为 ES5 代码,从而在现有环境下执行,即使用 ES6 编写代码而无需担心不能运行。
      简单的讲就是 一些 浏览器 不支持 ES6 部分语法,可以使用 Babel 转码器将 ES6 语法 转为 ES5 语法,从而被 浏览器 识别。
      比如:

        ES6 可以使用 箭头函数来 替代 普通函数,通过 Babel 转码器,可以将 箭头函数 转为 普通函数。这样就不需要去担心浏览器是否支持这种语法。

    【ES6】
        input.map(item => item + 1);
    
    【ES5】
        input.map(function (item) {
            return item + 1;
        });

    二、常用特性

    1、let 命令

    (1)基本内容
      let 命令通常用来声明局部变量。
      特性:局部有效、不存在变量提升、暂时性死区、不允许重复声明。

    (2)特性一:局部有效。
      let 命令类似于 var,用来声明变量,但是 var 是全局有效,let 只在其所在的代码块内生效,出了代码块就获取不到该值。

    如下例:(看的可能有点绕,多瞅两遍)
      var 定义的是全局变量,对于 for 循环来说,整个循环都只对一个 变量进行操作。看下面例子的第一个循环,在循环体内操作 i 会对循环有影响。由于进行了两次 i++,所以数组有部分值为 空,且只进行了部分循环。

      let 定义的是局部变量,对于 for 循环来说,每次循环都是不同的作用域,且 let 只对当前作用域有效。更有趣的是,循环语句内部是一个子作用域(即 在内部定义一个同名的 let 变量,不会影响外部的 let 变量)。看下面例子的第二个循环,每次循环操作,j 都是不同的值,且 循环内部 定义了 同名的 let 变量 j ,由于作用域的问题,其并不会影响循环语句中的 j,所以执行了全部循环。

    【举例:】
    
    var a = [];             // 用来记录每次循环需要打印的初始值
    var b = [];             // 用来记录每次循环的初始值
    var count = 0;          // 用来记录循环的次数
    
    for(var i = 0; i < 10; i++, count++) {
        a[i] = function() {
            console.log("当前循环的值 i 为:  " + i);
        };
        b[i] = I++;
    }
    console.log("当前循环执行次数为:  " + count);           // 由于 i 为全局变量,每次循环都会进行两次 i++,所以真实循环次数小于 10,所以输出为 5
    a[6]();                                                // 由于操作的都是同一变量,所以函数调用的是 最后一次修改的 i 值,所以输出为 10
    console.log("每次循环的初始值 i 为:  " + b);            // 用于只进行了部分循环,所有数组有些并没有赋值,即为空值。所以输出为 0,,2,,4,,6,,8
    console.log("循环执行后的 i 值:  " + i);                // i = 10 时退出循环, i 为全局变量,所以输出 为 10
    
    
    var c = [];            // 用来记录每次循环需要打印的初始值
    var d = [];            // 用来记录每次循环的初始值
    var count = 0;         // 用来记录循环的次数
    for(let j = 0; j < 10; j++, count++) {
        let j = 5;
        c[j] = function() {
            console.log("当前循环的值 j 为:  " + j);
        };
        d[j] = j++;
    }
    console.log("当前循环执行次数为:  " + count);           // 由于 j 为 局部变量,循环内部定义的 let 同名变量 j (子作用域)不会影响 循环语句的 j,真实循环执行 10 次,所以输出为 10
    c[5]();                                                // 每次操作都是不同的变量,且执行了 j++ 操作,所以输出为 6
    console.log("每次循环的初始值 j 为:  " + d);            // 由于内部每次都给 d[5] 赋值,其余元素均为空值,所以输出为  ,,,,,5
    console.log("循环执行后的 j 值:  " + j);                // 由于 j 为局部变量,只能存在于 for 循环代码块中, 所以此处会报错,输出 ReferenceError: j is not defined

    (3)特性二:不存在变量提升
      变量提升指的是 变量可以在声明前使用。
      let 不存在变量提升,即声明变量后,才可以使用该变量,不能在声明前使用,否则会报错。

    【举例:】
    
    console.log(a);     // 不报错,输出 undefined
    console.log(b);     // 报错,输出 ReferenceError: b is not defined
    var a = 10;
    let b = 20;

    (4)特性三:暂时性死区
      暂时性死区指的是 刚开始进入当前作用域,所要使用的变量就已经存在了,但是不可获取,当变量被声明后,才可以获取该变量。

    【举例:】
    
    var tmp = 123;
    console.log(tmp); //不报错,输出 123
    if (true) {
        console.log(tmp); // 报错,ReferenceError: Cannot access 'tmp' before initialization
        let tmp;
    }
    
    第一次定义 tmp 为 var 型,所以可以正常输出 123,
    进入 if 语句后,由于存在 let 定义的 tmp,系统判定 tmp 为局部变量而非全局变量。
    导致 console.log(tmp) 中 tmp 出现在 变量声明前(变量提升失败), 从而报错,此处即为暂时性死区。

    (5)特性四:不重复声明
      在同一块 let 作用域中,若使用 let 声明一个变量,则不能再重复声明同一个变量。

    // 报错,Identifier 'a' has already been declared
    {
        let a = 1;
        var a = 2;
    }
    
    // 不报错,undefined
    {
        var a = 1;
        var a = 2;
    }
    
    // 报错,Identifier 'a' has already been declared
    {
        let a = 1;
        let a = 2;
    }

    2、const 命令

    (1)基本内容
      const 通常用来声明一个只读的常量,一旦声明,常量的值不能被修改,且声明时必须初始化。
      用法类似于 let,局部有效、不存在变量提升、不重复声明。

    【举例:(常量值不可被修改)】
    
    const PI = 3.1415926
    console.log(PI);   // 输出 3.1415926
    PI = 3.14          // 报错,输出 Assignment to constant variable.
    
    【举例:(常量声明时需要初始化)】
    
    const a           // 报错,输出 Missing initializer in const declaration
    
    【举例:局部有效】
    {
        const PI = 3.1415926;
    }
    console.log(PI);   // 报错,输出 PI is not defined
    
    【举例:不存在变量提升】
    {
        console.log(PI);    // 报错,输出 Cannot access 'PI' before initialization
        const PI = 3.1415926;
    }
    
    【举例:不重复声明】
    {
        var PI = 3.14
        const PI = 3.1415926;  // 报错,输出 SyntaxError: Identifier 'PI' has already been declared
    }

      

    (2)若 const 声明的是对象,那么 其不变的是 指向对象的地址,对象的值仍可以改变。可以通过object.freeze() 方法冻结对象(即对象不可修改)。

    【举例:var,对象可被修改】
    {
        var f = {name : 'tom', age : '12'};
        console.log(f.name + ", " + f.age);   // tom, 12
        f.name = 'jarry';
        f.age = 44;
        console.log(f.name + ", " + f.age);  // jarry, 44
        f = {name : 'rick', age : '22'};
        console.log(f.name + ", " + f.age);  // rick, 22
    }
    
    【举例:const,对象内容可被修改,但是对象不可被修改】
    {
        const f = {name : 'tom', age : '12'};
        console.log(f.name + ", " + f.age);   // tom, 12
        f.name = 'jarry';
        f.age = 44;
        console.log(f.name + ", " + f.age);  // jarry, 44
        f = {name : 'rick', age : '22'};  // TypeError: Assignment to constant variable.
    }
    
    【举例:freeze,对象不可被修改,对象内容不可被修改】
    {
        const f = Object.freeze({name : 'tom', age : '12'});
        console.log(f.name + ", " + f.age);  // tom, 12
        f.name = 'jarry';
        f.age = 44;
        console.log(f.name + ", " + f.age);  // tom, 12
        f = {name : 'rick', age : '22'};  // TypeError: Assignment to constant variable.
    }

    3、解构表达式

    (1)什么是解构?
      解构指的是 ES6 支持按照一定的模式,从数组或者对象中提取值,并将提取的值 对变量进行赋值。

    (2)数组的解构赋值
      一般情况下,只要 = 左右两侧 的模式相同,左边的变量 就会赋值 上 右边对应的值。

    【未使用解构表达式给赋值:】
    let a = 10;
    let b = 20;
    let c = 30;
    console.log(a, b, c);
    
    【使用 解构表达式赋值:】
    let [a, b, c] = [100, 200, 300];
    console.log(a, b, c);

      解构不成功时,对应的数据为 undefined。
      允许解构赋值指定默认值,默认值可以为一个函数(惰性,用到时才调用)。

    【嵌套数组赋值:】
    
    let [a, [b, [c, d]]] =  [1, [2, [3, 4]]];
    console.log(a, b, c, d);         // 输出 1 2 3 4
    
    let [head, ...tail] = [1, 2, 3, 4];
    console.log(head);    // 输出 1
    console.log(tail);    // 输出 (3) [2, 3, 4]
    
    let [x, y, ...z] = [1];
    console.log(x);        // 输出 1
    console.log(y);        // 输出 undefined
    console.log(z);        // 输出 []
    
    【部分解构:(给匹配上的变量赋值)】
    
    let [x, y, z] = [1, 2];
    console.log(x);       // 输出 1
    console.log(y);       // 输出 2
    console.log(z);       // 输出 undefined
    
    let [a, [b], c] = [1, [2, 3], 4];
    console.log(a);       // 输出 1
    console.log(b);       // 输出 2
    console.log(c);       // 输出 4
    
    【解构时使用默认值:(即若赋值失败,可以使用默认值)】
    
    function hello() {
        return "hello";
    }
    
    let [x=hello(), y=hello(), z=100] = [1, 2, 3];
    console.log(x);               // 输出 1
    console.log(y);               // 输出 2
    console.log(z);               // 输出 3
    
    let [x2=hello(), y2=hello(), z2=100] = [, 2, ];
    console.log(x2);              // 输出 hello
    console.log(y2);              // 输出 2
    console.log(z2);              // 输出 100

    (3)对象的解构赋值
      对象同样可以进行解构。与数组解构不同的是,对象解构时根据属性名进行匹配,不需要注意顺序。
      属性名不匹配时,值为 undefined。
      可以自定义属性名,使用 : 去指定。
    如下例:
      let {name, age} 等价于 let {name: name, age: age}

    【根据属性名匹配:】
    
    let {name, age} = {name: "tom", age: 22};
    console.log(name);               // 输出 tom
    console.log(age);                // 输出 22
    
    【属性名匹配不成功,返回 undefined:】
    let {name2, age2} = {name: "tom", age: 22};
    console.log(name2);               // 输出 undefined
    console.log(age2);                // 输出 undefined
    
    【自定义属性名匹配:】
    let {name: name3, age: age3} = {name: "tom", age: 22};
    console.log(name3);               // 输出 tom
    console.log(age3);                // 输出 22

    4、字符串拓展

      即加强了字符串处理功能。
    (1)字符的 unicode 表示
      JavaScript 允许使用使用 uxxxx 的形式表示一个字符,其中 xxxx 表示 unicode 值。但是这种写法只支持 u0000 ~ uffff,超出这个限制需要使用 双字节 进行表示。
    比如:

      u1F680 会解析成 u1F68 和 0。若想正常显示,需使用双字节 uD83DuDE80 表示。

    【举例:】
    
    console.log("u0061");       // 输出 a
    console.log("u00614");      // 输出 a4

      ES6 可以使用 大括号将 xxxxx 括起来,从而正确解读。

    【举例:】
    
    console.log("u{0061}");
    console.log("u{1F680}");
    console.log("uD83DuDE80");

    (2)新增方法 -- includes()、startsWith()、endsWith()
      JavaScript 中通过 indexOf() 可以确定某个字符串中是否包含另外一个字符串。
      ES6 新增三个方法用于判断字符串中是否包含另一个字符串。
        includes() 返回布尔值,true 表示当前字符串中存在另一个字符串,false 表示不存在。
        startsWith() 返回布尔值,true 表示当前字符串的头部存在另一个字符串,false 表示不存在。
        endsWith() 返回布尔值,true 表示当前字符串的尾部存在另一个字符串,false 表示不存在。

    【举例:】
    
    let test = "hello world";
    console.log(test.includes("wo"));          // 输出 true
    console.log(test.startsWith("he"));        // 输出 true
    console.log(test.endsWith("ld"));          // 输出 true
    console.log(test.includes("helloworld"));  // 输出 false 

    (3)模板字符串(``)
      模板字符串是增强版的字符串,使用 反引号(``) 标识字符串,可以作为普通字符串使用,可以定义多行字符串,内部使用 ${} 可以嵌入变量、函数、表达式等并解析。

    【举例:】
    
    let [name, age] = ["tom", 32];
    function fun() {
        return "helloworld";
    }
    let test2 = `${name},
                age = ${age - 10},
                say ${fun()}`;
    console.log(test2);

    5、对象的拓展

      拓展对象的用法。
    (1)属性简写
      ES6 允许在 对象中 直接写变量,此时 属性为 变量名,属性值为 变量值。即 {a} 等价于 {a: a}

    【举例:】
    
    let a = "hello";
    let b = {a};
    console.log(b);      // 输出 {a: "hello"}
    
    let c = {a: a};
    console.log(c);      // 输出 {a: "hello"}
    
    let d = {g: "hello"};
    console.log(d);      // 输出 {g: "hello"}

      对象中的方法也可以简写。

    【举例:】
    
    let [name, age] = ["tom", 32];
    
    let person = {
        name,
        age,
        hello() {
            console.log(`${name}, ${age}`);
        },
        hello2: function() {
            console.log(`${name}, ${age}`);
        }
    };
    
    person.hello();
    person.hello2();

    (2)新增方法 -- assign()
      Object.assign() 方法用于对象的合并。
      其实现的是浅拷贝,即若 源对象中的某个属性值 仍是一个对象,那么目标对象 中拷贝得到的是这个对象的引用,即对源对象中这个对象进行修改,会影响到目标对象。

    【格式:】
        Object.assign(target, source1, ...source2);
    注:
        target 为目标对象,source1, ...source2 等都是源对象。
        该方法是将 源对象 的值 复制 到 目标对象 中。
        若出现同名属性,则后者会覆盖前者。
        即 target、source1、source2 中存在同名属性,则最后 target 的那个同名属性为 source2 的属性。
    
    【举例:】
    
    let tom = {
        name: "tom",
        age: 32,
        teacher: {
            chinese: "rose",
            english: "jack"
        }
    };
    
    let jarry = {
        name: "jarry",
        age: 33,
        email: "jarry@163.com"
    };
    
    let people = Object.assign({}, tom, jarry);
    
    console.log(people);
    
    tom.teacher.chinese = "rick";
    
    console.log(people);

    如何实现深拷贝嘞:
      有一种解决办法:(具体原因没有仔细深究)
        先将对象转为 json 字符串,再将 字符串转为对象。

    将上例
        let people = Object.assign({}, tom, jarry);
    改为
        let people = Object.assign({}, JSON.parse(JSON.stringify(tom)), jarry);

    (3)新增对象遍历方法 -- keys()、values()、entries()
      Object.keys() 获取对象 key 形成的数组。
      Object.values() 获取对象 value 形成的数组。
      Object.entries() 获取对象 key - value 形成的 二维数组。

    【举例:】
    
    let people = {
        name: "tom",
        age: 22
    };
    
    console.log(Object.keys(people));
    console.log(Object.values(people));
    console.log(Object.entries(people));

    (4)扩展运算符(...)
      用于取出对象、数组的参数并拷贝到当前对象中。
      若数据重复,会覆盖,等同于 Object.assign()。

    【举例:】
    
    let people = {
        name: "tom",
        age: 22
    };
    
    let people2 = {
        name: "jarry",
        age: 33
    };
    
    console.log({people, people2});
    console.log({...people, ...people2});
    
    
    let a = [3, 1, 2];
    console.log(a);
    console.log(...a);

    6、函数的拓展

    (1)函数参数默认值
      可以在定义函数的同时,指定函数的默认值,调用时,若未传递参数,则使用默认值。

    【举例:】
    
    function test (x, y) {
        y = y || "hello";
        console.log(x + "======" + y);
    }
    
    test("tom");                      // 输出 tom======hello
    test("tom", "helloworld");        // 输出 tom======helloworld
    
    
    function test2 (x, y = "hello") {
        console.log(x + "======" + y);
    }
    
    test2("tom");                     // 输出 tom======hello
    test2("tom", "helloworld");       // 输出 tom======helloworld

    (2)rest 参数
      rest 参数 ,形式为 ...变量名, 用于接收多个参数,保存在数组中。
      若有多个参数,则 rest 必须放在最后,否则会报错。

    【举例:】
    
    function test (...values) {
        // for of 每次获取的是数组的值
        for (let j of values) {
            console.log(j);
        }
    }
    
    test(8, 7, 9);
    
    function test2 (...values) {
        // for in 每次获取的是数组的下标
        for (let j in values) {
            console.log(values[j]);
        }
    }
    test2(8, 7, 9);
    
    function test3 (...values, y) {            // 报错,SyntaxError: Rest parameter must be last formal parameter
        for (let j in values) {
            console.log(values[j]);
        }
    }

    (3)箭头函数
      ES6 支持 使用 箭头 => 定义函数。

    【使用箭头函数定义 函数:】
    
    var f = v => v;
    console.log(f(3));   // 3
    
    // 等价于
    var f = function(v){
        return v;
    }
    console.log(f(3)); // 3

      如果没有参数、或者有多个参数,需使用圆括号 () 代替参数部分。
      如果方法体(代码块)只有一条语句,则 return 可以省略。

    【使用 () 代替参数:】
    
    var f = () => 5;
    // 等价于
    var f = function () {
        return 5
    };
    
    
    var sum = (num1, num2) => num1 + num2;
    // 等价于
    var sum = function(num1, num2) {
        return num1 + num2;
    };

      如果方法体(代码块)存在多条语句,则需要使用大括号 {} 括起来,并使用 return 返回值。

    【举例:】
    
    var fun = () => {
        let num = 7;
        let num2 = num + 3;
        return num + num2;
    };
    console.log(fun());  // 17
    
    // 等价于
    var fun = function() {
        let num = 7;
        let num2 = num + 3;
        return num + num2;
    };
    console.log(fun());   // 17

      若返回的是一个对象,则必须在对象外面加上圆括号 (),否则 {} 会被当成代码块被解析。

    【举例:】
    
    var getPeopleItem = id => ({ id: id, name: "Temp" });
    console.log(getPeopleItem(3));   // {id: 3, name: "Temp"}
    
    var getPeopleItem = id => { id: id, name: "Temp" };
    console.log(getPeopleItem(3)); //  SyntaxError: Unexpected token :

      解构与箭头函数可以一起使用:

    【举例:】
    
    let people = {
        name: "tom",
        age: 22
    };
    
    let fun = (param) => {
        console.log(param.name + "==========" + param.age);
    };
    fun(people);
    
    let fun2 = ({name, age}) => {
        console.log(name + "==========" + age);
    };
    fun2(people);

    7、数组常用方法

      参考:https://www.cnblogs.com/l-y-h/p/12150578.html
    (1)新增方法 -- reduce()
      Array.reduce(callback[, initialValue]) 用于给数组的每一个元素执行一个回调函数。
    其中 :
      initialValue 为第一次执行 callback 时的参数值,可以省略。
      callback 有四个参数,callback(previousValue, currentValue, index, array).
      previousValue 指上一次执行回调的函数值,或者初始值。
      currentValue 指数组当前被处理的元素
      index 指当前数组元素的下标
      array 指当前的数组

    【举例:】
    
    let arr = [4, 6, 5];
    
    let newArr = arr.reduce((previousValue, currentValue, index, array) => {
        console.log("上一次处理的值为: " + previousValue);
        console.log("当前处理的值为: " + currentValue);
        console.log("当前元素下标为: " + index);
        console.log("当前数组元素为: " + array[index]);
        return currentValue * 2;
    });
    
    console.log(newArr);

    8、Promise 对象

    (1)什么是 Promise ?
      Promise 是一个异步编程的一种解决方案。可以理解为一个容器,里面保存着未来才会结束的某个操作(异步操作)的结果,通过 Promise 对象可以获取异步操作的消息。

    (2)Promise 特点
    特点一:对象的状态不受外界影响。
     Promise 有三种状态,Pending (进行中)、Resolved (解决)、Rejected (失败)。只有异步操作的结果能决定 Promise 处于哪种状态,其余操作无法改变该状态,无法中途取消操作。

    特点二:状态改变后,不再变化。
      状态改变的情况,Pending -> Resolved 、 Pending -> Rejected。
      一旦状态改变,其不会再改变。

    (3)Promise 缺点
      无法取消Promise,一旦新建便会执行,无法中途取消。
      如果不设置回调函数,Promise内部的错误不会向外抛出。
      处于Pending时,无法判断该操作是刚开始还是即将完成。

    (4)如何使用?
      需要使用 new 去实例化一个 Promise 对象,参数为 一个函数。
      函数的参数为 resolve、reject ,参数为两个函数,由 JavaScript 引擎提供。
      resolve 函数是改变状态, Pending -> Resolved ,即异步操作成功后调用,并将异步操作的成功结果作为参数向外传递。
      reject 函数也是改变状态, Pending -> Rejected,即异步操作失败后调用,并将异步操作的失败结果作为参数向外传递。
      使用 then 方法可以处理 resolve、reject 传递出来的结果。其接受两个回调函数作为参数。第一个回调函数用来处理 resolve 传递的结果,第二个回调函数用来处理 reject 传递的结果。第二个回调函数可选。
      一般情况下,使用 catch 方法处理 reject 传递出来的结果。其作用等价于 then 方法中的第二个回调函数。

    【格式:】
    
    var promise = new Promise((resolve, reject) => {
        if(异步操作成功) {
            resolve(data);
        } else {
            reject(error);
        }
    });
    
    promise.then((data) => {
        // 成功的操作
    }).catch((error) => {
        // 失败的操作
    });

    9、模块化

    (1)什么是模块化?

      模块化就是把代码进行拆分,方便重复利用。类似于 Java 中的各种 jar 包。
      模块化两个主要命令:export、import。
        export:用于规定模块的对外接口,即通过 export 可以获取模块的内容。
        import:用于导入模块,即通过 import 可以与其他模块建立起联系。

    (2)export 命令
      通常一个模块就是一个文件,该文件内部的变量、数组、对象 等外界都不能获取。需要使用 export 将其导出。
      export 可以导出 基本类型变量、函数、数组、对象等。

    【导出方式一:】
    
    export var test = "hello";
    
    【导出方式二:】
    
    var a = "hello";
    var b = [1, 2, 3];
    export {a, b};
    
    导出方式一、导出方式二 对外暴露的接口名 为 变量名、函数名等。
    使用 import 要填写正确的接口名,才能正常引用模块,否则会出错。
    
    【导出方式三:(使用 as 自定义接口名)】
    
    var a = "hello";
    var b = [1, 2, 3];
    export {
        a as AA,
        b as BB
    };
    
    【导出方式四:(使用 default 可以忽略接口名,此时 import 可以自定义接口名)】
    
    export default {
        var a = "hello";
        var b = [1, 2, 3];
    }

    (3)import 命令
      export 定义了模块对外的接口后,可以使用 import 导入相应的模块功能。

    【导入方式一:(使用 {} 可以一次接受多个模块接口名)】
    
    import {a, b} from 'xx/xx.js';
    
    【导入方式二:(使用 as 取名)】
    
    import {a as AA, b as BB} from 'xx/xx.js';
    
    【导入方式三:(对于 export default 的模块,可以任意取名)】
    
    import test from 'xx/xx.js';
  • 相关阅读:
    SpringBoot自定义HttpMessageConverter
    第一次使用Linux服务器所栽之坑
    入门Nginx
    HttpClient中的Timout
    SpringBoot启动
    SpringBoot注解
    百度2017春招笔试
    学习JUnit
    Mybatis中的@SelectKey注解
    PHP中MD5函数漏洞
  • 原文地址:https://www.cnblogs.com/huoyz/p/14377993.html
Copyright © 2011-2022 走看看