ES6常用特性

作者: 方千竹 | 来源:发表于2017-12-15 23:22 被阅读790次

    1、什么是ECMAScript6?和JavaScript什么关系?

    1.1 什么是ECMAScript6?

    首先说一下什么是ECMA(European Computer Manufacturers Association)欧洲计算机制造商协会。

    如果说ECMA是一种组织,那么ECMAScript 就是这个组织推出的一个脚本(script)的标准。

    ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准。因为当前版本的ES6是在2015年发布的,所以又称ECMAScript 2015。

    1.2 ECMAScript6和JavaScript的关系?

    JavaScript的核心就是ECMAScript,包括ActionScript
    但是JavaScript由ECMAScript、DOM和BOM三部分组成

    2、常用特性有?

    • let、const 及var的不同
    • Destructuring 解构赋值
    • arrow function 箭头函数
    • template string 模板字符串
    • class、extends、super
    • default、rest
    • 总结
    2.1 let、const和var之间的异同
    • let变量 有块级作用域,没有var的变量提升,不能重复声明覆盖
    • var变量 有函数作用域,有变量提升,可以重复声明覆盖
    • const常量 声明后不可再修改的,不可以重复声明覆盖
    es6里面不建议使用var了,因为var定义的变量没有块级作用域,
    还会出现变量提升的情况,这样经常会导致你意想不到的错误,而let就不会这样.
    const是定义那些不可以被重新赋值的变量,let是定义普通的变量。
    

    var的变量提升和let比较,也就说let修复了var存在的一些bug。

    
        console.log(name1); // 可以输出到控制台
        console.log(name2); // 不可以输出到控制台
    
        var name1 = "Tom"; // var有变量提升
        let name2 = "Jerry"; // let没有变量提升
    

    var变量只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景。第一种场景就是你现在看到的内层变量覆盖外层变量。而let则实际上为JavaScript新增了块级作用域。用它所声明的变量,只在let命令所在的代码块内有效

            
        var name = "Tom";
        console.log(name);  // Tom
        var name = "Tom2";
        console.log(name);  // Tom2
    
        while (true) {
            var name = "Jerry";
            console.log(name);  //Jerry
            break;
        }
    
        console.log(name);  //Jerry
    

    let变量不可以重复声明覆盖

        let name = "Tom";
        let name = "Tom2";//此处报错
    
    Uncaught SyntaxError: Identifier 'name' has already been declared
    

    let变量是块级作用域

        let name = "Tom";
    
        while (true) {
            //let是块级作用域 变量name只在此代码块内有效
            let name = "Jerry";
            console.log(name);  //Jerry 
            break;
        }
    
        console.log(name);  //Tom
    
    

    另外一个var带来的不合理场景就是用来计数的循环变量泄露为全局变量

    
        var a = [];
        for (var i = 0; i < 10; i++) {
          a[i] = function () {
            console.log(i);
          };
        }
        a[6](); // 10
    
        var a = [];
        for (let i = 0; i < 10; i++) {
          a[i] = function () {
            console.log(i);
          };
        }
        a[6](); // 6
    
    按钮的onclick事件场景

    因为var不是块级作用域,所以此次声明的变量i,在整个作用域内有效,
    针对这种情况,可以用闭包或let变量声明来处理按钮点击事件的问题。

        var btns = document.querySelectorAll("button");
        console.log(btns.length);
        for(var i=0;i<btns.length;i++){
            console.log(i);
            btns[i].onclick = function(){
                alert("点击了第"+i+"个按钮!");
            }
        }
        
        //修改成let声明的方式
        var btns = document.querySelectorAll("button");
        console.log(btns.length);
        for(let i=0;i<btns.length;i++){
            console.log(i);
            btns[i].onclick = function(){
                alert("点击了第"+i+"个按钮!");
            }
        }
    

    const也是用来声明常量,一旦声明,常量的值就不可变化

    const PI = Math.PI
    
    PI = 23 //Module build failed: SyntaxError: /es6/app.js: "PI" is read-only
    

    const有一个很好的应用场景,就是当我们引用第三方库的时声明的变量,用const来声明可以避免未来不小心重命名而导致出现bug:

    const moment = require('moment');
    
    注:在代码中,建议首选const声明,如果某个变量值是需要修改的,可以选择let变量声明。有利于js中的模块化开发。
    
    2.2 Destructuring 解构赋值

    解构赋值:就是从对象或数组中提取值,对变量进行赋值,被称为解构(Destructuring)

    2.2.1 从对象中提取值

            
        let cat = "Tom";
        let mouse = "Jerry";
        let zoo = { cat: cat, mouse: mouse}
    
        console.log(zoo);
        console.log(zoo.cat + " and " + zoo.mouse);
        
        //同样也可以写成下面的格式
        let cat = "Tom";
        let mouse = "Jerry";
        let zoo = { cat, mouse}
    
        console.log(zoo);
        console.log(zoo.cat + " and " + zoo.mouse);
        
        //还有这种格式
        let cat2 = { type: 'animal', many: 2}
        let { type, many } = cat2;
        console.log(type,many); // animal  2
    
    

    2.2.2 从数组中提取值

    //完全解构
    let [a,b,c] = [1,2,3];
    console.log(a+","+b+","+c); // 1,2,3
    
    let [foo,[[bar],baz]] = [1,[[2],3]];
    console.log(foo+","+bar+","+baz); // 1,2,3
    
    let [x,,y] = [1,2,3];
    console.log(x + "," + y); //1,3
    
    let [head,...tail] = [1,2,3,4,5];
    console.log(head); // 1
    console.log(tail); // [2,3,4,5]
    
    //不完全解构
    
     let [x,y] = [1,2,3];
     console.log(x+","+y);// 1,2
    
     let [a,[b],d] = [1,[2,3],4];
     console.log(a+","+b+","+d); // 1,2,4
    
    

    2.2.3 解构赋值的用处

    • 交换变量的值
    • 从函数返回多个值
    • 函数参数的定义
    • 提取JSON数据
    • 函数参数的默认值
    • 遍历Map结构
    • 输入模块的指定方法

    1)交换变量的值

    let x = 1;
    let y = 2;
    [x,y] = [y,x];
    console.log(x + "," + y); // 2,1
    
    
    1. 从函数返回多个值

    函数只能返回一个值,如果要返回多个值,就要把值放在数组或对象里面返回。有了解构赋值就非常简单了

    function example() {
        return [1,2,3];
    }
    
    let [a,b,c] = example();
    console.log(a,b,c); // 1 2 3
    
    function example2() {
        return {
            x: 111,
            y: 222,
            z: 333
        }
    }
    
    let {x,y,z} = example2();
    console.log(x,y,z); // 111 222 333
    
    1. 函数参数的定义
    function f([x,y,z]) {
        return x + y + z;
    }
    
    console.log(f([1,2,3])); // 6
    
    function f1({x,y,z}){
        return x + y +z;
    }
    console.log(f1({y:3,z:2,x:1})); // 6
    
    1. 提取JSON数据
    let jsonData = {
        id: 2,
        status: 'ok',
        data: [123,456]
    };
    let { id,status,data: number } = jsonData;
    console.log(id+","+status+","+number); // 2,ok,123,456
    
    1. 函数参数的默认值
    jQuery.ajax = function (url, {
      async = true,
      beforeSend = function () {},
      cache = true,
      complete = function () {},
      crossDomain = false,
      global = true,
      // ... more config
    }) {
      // ... do stuff
    };
    
    1. 遍历Map结构
    const map = new Map();
    map.set('first','hello');
    map.set('second','world');
    
    for(let [key,value] of map){
        console.log(key + " is " + value);
    }
    
    1. 输入模块的指定方法

    加载模块时,往往需要指定哪些输入方法。使用解构赋值如下:

    const { sourcemap,sourcenode } = require('source-map');
    
    2.3 箭头函数

    2.3.1 箭头函数

    使用“=>”来定义函数.如下是相同的两种函数声明方式

    //箭头函数 
    var f = v => v;
    
    //普通函数
    var f = function f(v) {
        return v;
    }
    

    2.3.2 箭头函数的参数

    1. 如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。
    var f = () => 5;
    //等同于如下
    var f = function() {
        return 5;
    }
    
    //需要多个参数
    var f = (num1,num2) => num1 + num2;
    //等同于
    var f = function (num1,num2){
        return num1 + num2;
    }
    
    //如果箭头函数多与一条语句,就使用大括号将他们扩起来
    var f = () => {
        let a = 1;
        let b = 3;
        return a + b;
    }
    
    //由于{}被解释为代码块,箭头函数直接返回一个对象,需要在对象外面加上括号,否则会报错
    let retObject = id => ({ id:1, name: "Tom"});
    
    //变量函数可以与解构赋值结合使用
    const f = ({ first,second }) => first + " " + second;
    //等同于
    const f = function(person) {
        return person.first + " " + person.second;
    }
    
    
    1. 使用箭头函数,有时一行代码就能定义一个简单的工具函数。如下:
    const square = n => n * n;
    console.log(square(2));
    console.log(square(3));
    

    箭头函数的一个用处,就是用来简化回调函数

    1. 箭头函数能处理this指向的问题

    长期以来,JavaScript语言的this对象一直是一个令人头痛的问题,在对象方法中使用this,必须非常小心。但是使用箭头函数后,要担心的问题就解决了。

    使用普通函数

    class Animal {
        constructor() {
            this.type = 'animal';
        }
        says(say) {
            setTimeout(function(){
                //此处this指向的是全局对象,而不是animal对象
                console.log(this.type + " says " + say);
                console.log(this); // windows对象
            },1000)
        }
    }
    
    var animal = new Animal();
    animal.says('hello'); // undefined says hello
    

    使用箭头函数

    class Animal {
        constructor() {
            this.type = 'animal';
        }
        says(say) {
            //使用箭头函数
            setTimeout( () => {
                //此处this指向的Animal对象
                console.log(this.type + " says " + say);
                console.log(this); //Animal对象
            },1000);
        }
    }
    
    var animal = new Animal();
    animal.says('hello'); // animal says hello
    

    不使用箭头函数

    //this重指向
    class Animal {
        constructor() {
            this.type = 'animal';
        }
        says(say) {
            //此处this指向的Animal对象
            console.log(this);
            const self = this;
            setTimeout(function(){
                //此处self.type就是构造方法中的值
                console.log(self.type + " says " + say);
                console.log(this); // windows对象
            },1000)
        }
    }
    
    var animal = new Animal();
    animal.says('hello'); // animal says hello
    
    var animal = new Animal();
    animal.says('koook'); // animal says koook
    
    //方法bind this,生成一个新的对象
    class Animal {
        constructor() {
            this.type = 'animal';
        }
        says(say) {
            //此处this指向的Animal对象
            console.log(this);
            // const self = this;
            setTimeout(function(){
                //此处self.type就是构造方法中的值
                console.log(this.type + " says " + say);
                console.log(this); // Animal对象
            }.bind(this),1000)
        }
    }
    
    var animal = new Animal();
    animal.says('hello'); // animal says hello
    
    

    箭头函数使用注意点

    • 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
    • 不可以当做构造函数,不可以使用new命令,否则会抛出一个错误
    • 不可以使用arguments对象,该对象在函数体内不存在。如果要使用,可以用rest参数代替
    • 不可以使用yield命令,因此箭头函数不能用作Generator函数
    2.4 模板字符串(template string)

    当我们要插入大段的html内容到文档中时,传统的写法非常麻烦;如下:

    //不使用模板字符串
    const tempStr = "There are <b>" + '3' + "</b> " +
      "items in your basket, " +
      "<em>" + '$50.00' +
      "</em> are on sale!";
    
      const tempNode = document.getElementById('app');
      console.log(tempNode);
      tempNode.innerHTML = tempStr;
      
      //使用模板字符串
    const tempStr = `
      There are <b>3</b> items
       in your basket, <em>$50.00</em>
      are on sale!`;
    
      const tempNode = document.getElementById('app');
      console.log(tempNode);
      tempNode.innerHTML = tempStr;
    
    2.5 class extends super

    ES6提供了更接近传统语言的写法,引入了Class(类)这个概念。新的class写法让对象原型的写法更加清晰、更像面向对象编程的语法,也更加通俗易懂。

    //定义Animal类
    class Animal {
        //构造方法内定义的方法和属性是实例对象自己的
        //构造方法为定义的方法和属性是所有实例对象共享的
        constructor() {
            this.type = 'animal';
        }
        says (say) {
            console.log(this.type + " says " + say);
        }
    }
    
    //实例化Animal对象
    let animal = new Animal();
    //animal对象调用says方法
    animal.says('hello');// animal says hello
    
    //定义Cat类,并继承Animal类
    class Cat extends Animal {
        //子类的构造方法先调用父类的构造方法
        constructor() {
            //指代父类的实例(即父类的this对象)
            super();
            this.type = 'cat';
        }
    }
    
    //实例化Cat对象
    let cat = new Cat();
    //cat对象调用父类的says方法
    cat.says('miaomiao');// cat says miaomiao
    

    上面代码首先用class定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象。简单地说,constructor内定义的方法和属性是实例对象自己的,而constructor外定义的方法和属性则是所有实例对象可以共享的。

    Class之间可以通过extends关键字实现继承,这比ES5的通过修改原型链实现继承,要清晰和方便很多。上面定义了一个Cat类,该类通过extends关键字,继承了Animal类的所有属性和方法。

    super关键字,它指代父类的实例(即父类的this对象)。子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。

    ES6的继承机制,实质是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this。

    2.6 default、rest参数

    2.6.1 default的写法

    //es5及之前的default写法
    function animal(type) {
        type = type || 'cat';
        console.log(type);
    }
    animal(); // cat
    animal("mouse"); // mouse
    
    //es6的default写法
    const animal2 = (type='cat') => console.log(type);
    animal2(); // cat
    animal2("dog"); // dog
    

    2.6.2 rest参数

    rest参数(...变量名),用于获取函数的多余参数,这样就不需要使用Arguments对象了。rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中。

    
    function add (...values) {
        let sum = 0;
    
        for(let val of values) {
            sum += val;
        }
        console.log(sum);
        return sum;
    }
    
    add(1,2,3);
    
    

    rest参数之后,不能再有其它参数

    //error
    function f(a,...b,c) {
        ...
    }
    

    相关文章

      网友评论

      本文标题:ES6常用特性

      本文链接:https://www.haomeiwen.com/subject/caejwxtx.html