资讯专栏INFORMATION COLUMN

ES6

keithxiaoy / 681人阅读

摘要:返回布尔值,表示参数字符串是否在源字符串的尾部。我们可以往里面添加删除查询数据先声明一个对象往这个集合对象中添加元素判断集合中是否存在一个元素返回一个布尔值,表示该值在中存在与否。

一、 ES6 基本语法 1.1 let

作用域就是一个变量的有效的范围,就是你声明一个变量以后,这个变量在什么场合可以使用它。以前JavaScript只有全局作用域函数作用域,现在JavaScript也有了块级作用域(block scope)

1.1.1 let 语法
let var1 [= value1] [, var2 [= value2]] [, ..., varN [= valueN]];
1.1.2 参数解释
var1, var2, …, varN 变量名。可以是任意合法的标识符。
value1, value2, …, valueN 变量的初始值。可以是任意合法的表达式。
1.1.2 let 描述

let允许你声明一个作用域被限制在块级中的变量、语句或者表达式。与var关键字不同的是,它声明的变量只能是全局或者整个函数块的。

1.1.3 let 作用域规则
let声明的变量只在其声明的块或子块中可用,这一点,与var相似。二者之间最主要的区别在于var声明的变量的作用域是整个封闭函数。

看下面的例子:

            function varTest() {
              var x = 1;
              if (true) {
                var x = 2;  // 同样的变量!
                console.log(x);  // 2
              }
              console.log(x);  // 2
            }

        function letTest() {
              let x = 1;
              if (true) {
                let x = 2;  // 不同的变量
                console.log(x);  // 2
              }
              console.log(x);  // 1
        }
1.2 const 1.2.1 const 语法
const name1 = value1 [, name2 = value2 [, ... [, nameN = valueN]]];
1.2.2 参数解释
nameN
常量名称,可以是任意合法的标识符。

valueN
常量值,可以是任意合法的表达式。

1.2.3 const描述
此声明创建一个常量,其作用域可以是全局或本地声明的块。 与var变量不同,全局常量不会变为窗口对象的属性。需要一个常数的初始化器;也就是说,您必须在声明的同一语句中指定它的值(这是有道理的,因为以后不能更改)。
const声明创建一个值的只读引用。但这并不意味着它所持有的值是不可变的,只是变量标识符不能重新分配。例如,在引用内容是对象的情况下,这意味着可以改变对象的内容(例如,其参数)。
1.2.4 实例
    
1.2.5 小结
    如果const后面的变量是普通变量,改变值报错。如果后面存储的是数组或者对象,那么改变它的指向也会报错,但是如果改变数组或者对象的值是不会发生错误的
    
    

1.3 解构赋值
ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构
1.3.1 数组的解构赋值

ES5 中的变量赋值,只能直接指定值

    var a = 1;
    var b = 2; 
    var c = 3;

ES6 可以这样写

    var [a, b, c] = [1, 2, 3];
      console.log(a,b,c);// 1 2 3

上面代码表示,可以从数组中提取值,按照对应位置,对变量赋值。这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值

1.3.2 允许使用默认值
    var [a=1] = []
        console.log(a);// 1
        var [a,b=2] = [3];
        console.log(a,b);//3 2
        var [a,b=4] = [5,undefined];
        console.log(a,b);// 5 4
1.3.4 使用默认值的注意事项

注意一:

ES6内部使用严格相等运算符(===),判断一个位置是否有值。    所以,如果一个数组成员不严格等于undefined,默认值是不会生效的。
    var [d=8] = [undefined];
    console.log(d);// 8
    var [a=9] = [null];
    console.log(a);// null

上面代码中,如果一个数组成员是null,默认值就不会生效,因为null不严格等于undefined。

注意二:

如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值。
    function getNumber(){
            console.log("只有用到我的时候我才出现");
        }
        var [a=getNumber()] = ["我先来"];
        console.log(a);// 会输出 我先来

上面代码中,因为a能取到值,所以函数f根本不会执行。上面的代码其实等价于下面的代码。

    function getNumber(){
            console.log("只有用到我的时候我才出现");
        }
        let a;
        if(["我先来"][0]===undefined){
            a = getNumber();
        }else{
            a = ["我先来"][0];
        }
        console.log(a);// 会输出  我先来

注意三:

默认值可以引用解构赋值的其他变量,但该变量必须已经声明
    let [a,b=a]=[1];
        console.log(a,b);// a = 1 b = 1
        let [x=2,y=x]=[];
        console.log(x,y);// x = 2 y = 2
        let [c=1,d=c]=[12,3];
        console.log(c,d);// c =12 d = 3
        let [e=f,f=1]=[];
        console.log(e,f);// 报错 f is not defined

上面最后一个表达式之所以会报错,是因为e用到默认值f时,f还没有声明

1.3.5 对象的解构赋值
解构赋值不仅可以用于数组,还可以用于对象.

eg:

    let {name,age} = {name:"wxk",age:20};
        console.log(name);    // wxk

注意:对象的解构与数组有一个重要的不同

- 数组的元素是按次序排列的,变量的取值由它的位置决定
- 对象的属性没有次序,变量必须与属性同名,才能取到正确的值

小编总结:等号左边的变量的次序,与等号右边两个同名属性的次序不一致,但是对取值完全没有影响。但是如果变量没有对应的同名属性,则会导致取不到值,最后等于undefined
1.4 函数 1.4.1 为函数的参数设置默认值
在es6里面我们可以给定义的函数接收的参数设置默认的值,如果不去指定这个函数的参数的值的话,就会使用这些参数的默认的值
    function  Person(name="Tom",age=12){
            console.log(name);//Tom
            console.log(age);// 12
        }
        Person();

如果在调用函数的时候传入实参,则会改变默认参数的值。eg:

function  Person(name="Tom",age=12){
            console.log(name);//Jack
            console.log(age);// 20
        }
        Person("Jack",20);
1.4.2 ... 操作符
...是es6中新添加的一种操作符,可以叫做spread(扩展)或则rest(剩余)

具体用法如下:

rest (剩余操作符)

剩余操作符一般会用在函数的参数里面。比如:
想让一个函数支持更多的参数,参数的数量不受限制,这个时候就可以 使用剩余操作符。

eg:

    

剩余操作符后面的变量会变成一个数组,多余的参数会被放入这个数组中

spread(扩展运算符)

...操作符如果用在数组的前面,作用就是将这个数组展开,因此称为扩展操作符。相当于rest操作符的逆运算

eg:

    

这里呢把数组arr1 和 数组 arr2 用 ... 操作符进行了扩展,所有他们变成了字符串,不信你们可以尝试一下,直接输出 console.log(...arr1)

1.4.3 函数的 name 属性
es6给函数添加了一个name属性,使用这个属性我们可以得到函数的名字

eg:

    
1.4.4 箭头函数(重点) 箭头函数的语法

不引入参数

    

2. 引入单个参数

    
1.4.5 箭头函数的 this 指向
箭头函数本身是没有this和arguments的,在箭头函数中引用this实际上是调用的是定义时的上一层作用域的this。
这里强调的是上一层作用域,是因为对象是不能形成独立的作用域的。

看下面的小例子更容易明白:

eg1

    

eg2:

    var ojb = {
            pro: {
                getPro: ()=>{
                    console.log(this);
                }
            }
        }
        ojb.pro.getPro();//this指向的是window,因为箭头函数定义时,getPro的上一级是pro,是一个对象,不能形成多带带的作用域,故指向window。

总结箭头函数的this指向:箭头的this,向上找,找到非箭头函数,看一下这个非箭头函数的this是谁,那么箭头函数的this就是这个非箭头函数的this。

1.5 字符串 1.5.1 includes(), startsWith(), endsWith()
传统上,JavaScript只有indexOf方法,可以用来确定一个字符串是否包含在另一个字符串中。ES6又提供了三种新方法。
includes():返回布尔值,表示是否找到了参数字符串。
startsWith():返回布尔值,表示参数字符串是否在源字符串的头部。
endsWith():返回布尔值,表示参数字符串是否在源字符串的尾部。

举例说明三个方法怎么用:

    

注意:这三个方法都支持第二个参数,表示开始搜索的位置

1.5.2 模板字符串

模板字符串中所有的空格、新行、缩进,都会原样输出在生成的字符串中

    

注意:模板字符串(template string)是增强版的字符串,用反引号(`),标识,嵌入的变量名写在${}之中

1.6 对象 Object 1.6.1 属性的简洁表示法
    

ES6为我们提供了一种简写方法,就是在对象里面直接加上这属性,不需要再指定值

1.6.2 对象新增函数Object.is()
ES5比较两个值是否相等,只有两个运算符:相等运算符(==)和严格相等运算符(===)。它们都有缺点,前者会自动转换数据类型,后者的NaN不等于自身,以及+0等于-0。JavaScript缺乏一种运算,在所有环境中,只要两个值是一样的,它们就应该相等。
ES6提出“Same-value equality”算法,用来解决这个问题。Object.is就是部署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。

见下面的例子:

    
1.6.3 对象新增函数Object.assign()
Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)
    

1. 注意:如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后 面的属性会覆盖前面的属性

    

2. 如果只有一个参数,Object.assign会直接返回该参数

    var cat = {
            height:50
        }
        var str = {}
        Object.assign(str,cat);
        console.log(str);//{height: 50}

3. 如果该参数不是对象,则会先转成对象,然后返回

    console.log(Object.assign(2));// Number {2}

4. 由于undefined和null无法转成对象,所以如果它们作为参数,就会报错。

1.7 集合对象 1.7.1 Set 对象

Set对象是一组值的集合,这些值是不重复的,无序的,与我们在数学中学到的集合是一样的。我们可以往里面添加、删除、查询数据

1. 先声明一个Set对象

var mySet = new Set();

2. 往这个集合对象中添加元素

mySet.add(1);
mySet.add("some text");

3. 判断集合中是否存在一个元素1

mySet.has(1); // true  返回一个布尔值,表示该值在Set中存在与否。

4. 删除集合中的字符串

mySet.delete("foo");//移除Set的中与这个值相等的元素

5. 获取集合中元素的数量

mySet.size; // 返回Set对象的值的个数。

6. 删除集合中所有的元素

mySet.clear();//移除Set对象内的所有元素。
    

1.7.2 Map对象
如果你需要一个键值对的数据结构,我们可以声明一个Map对象,这个对象里面可以包含多个项目,每个项目都有一个名字,还有一个跟它对应的值

1. 创建Map对象的方法是使用new操作符去声明这个对象

var myMap = new Map();

2. 向Map对象里面添加键值对,其中键和值可以是任意值(对象或者原 始值)

var obj = {};
var fun = function(){};
var str = “HelloWorld”;
myMap.set(obj, “我是对象”);
myMap.set(fun, “我是函数”);
myMap.set(str, “我是字符串”);

3. 查看集合中元素的数量

myMap.size

4. 获取相应的键值

myMap.get(obj);

5. 删除一个键值对,然后再判断该键值对是否存在

myMap.delete(fun);
myMap.has(fun);

6. 删除Map集合中所有的键值对

myMap.clear();

eg:

    

其余的方法就不演示了,和上面的Set方法一样

1.7.3 Class (重点)
    
ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。上面的代码就可以这样改
    class person {
            constructor(name,age){
                this.name = name;
                this.age = age;
            }
            run(){
                console.log("每天坚持锻炼");
            }
        }
        var student = new person("Jack",15);
        student.run();

小编分析:上面代码定义了一个“类”,可以看到里面有一个constructor方法, 这就是构造方法,而this关键字则代表实例对象。也就是说,ES5的构造函数person,对应ES6的person类的构造方法。person类除了构造方法,还定义了一个run方法。注意,定义“类”方法的时候,前面不需要加上function这个关键字,直接把函数定义放进去了就可以了。另外,方法之间不需要逗号分隔,加了会报错。构造函数的prototype属性,在ES6的“类”上面继续存在。事实上,类的所有方法都定义在类的prototype属性上面

1.7.4 class继承 (重点)
    

extends关键字用于实现类之间的继承。子类继承父类,就继承了父类的所有属性和方法,使用super可以调用父类的方法

1.8 Promise对象 1.8.1 什么是Promise对象
一个 Promise 对象可以理解为一次将要执行的操作(常常被用于异步操作),使用了 Promise 对象之后可以用一种链式调用的方式来组织代码,让代码更加直观。而且由于 Promise.all 这样的方法存在,可以让同时执行多个操作变得简单

下面简单介绍Promise 对象,如下代码:

    
上面的代码实现的功能非常简单,helloWord 函数接受一个参数,如果为 true 就打印 "Hello World!",如果为 false 就打印错误的信息。helloWord 函数返回的是一个 Promise 对象。

在 Promise 对象当中有两个重要方法————resolve 和 reject。
resolve 方法可以使 Promise 对象的状态改变成成功,同时传递一个参数用于后续成功后的操作,在这个例子当中就是 Hello World!字符串
reject 方法则是将 Promise 对象的状态改变为失败,同时将错误的信息传递到后续错误处理的操作

1.8.2 Promise的三种状态

resolved 可以理解为成功的状态

rejected 可以理解为失败的状

pending promise对象实例创建时候的初始状态

helloWorld 的例子中的 then 方法就是根据 Promise 对象的状态来确定执行的操作,resolve 时执行第一个函数(onFulfilled),reject 时执行第二个函数(onRejected)

如何查看Promise对象的方法,在控制台输出 new Promise(function(){})
见下图:

### 1.8.3 使用Promise处理多任务

看下面的例子:

    function HelloWorld(ready){
           return new Promise(function(resolve,reject){
               if(ready){
                   resolve("HelloWorld");
               }else{
                   reject("GoodBay");
               }
           });
       }
       HelloWorld(true).then(function(message){
           console.log(message);
       },function(error){
           console.log(error);
       }).then(function(){
           console.log("你好,世界!");
       }).then(function(){
           console.log("讲真的");
       });
解析:可以看到后面的方法用了链式的方式进行编程,这是因为,then返回的还是一个 Promise 对象,因此返回的对象依然具有 then 方法,并且返回的对象状态是  resolved, 所以后面的 then方法全部是执行then 方法中的第一个函数参数
1.8.4 catch方法
        
catch 方法是 then(onFulfilled, onRejected) 方法当中 onRejected 函数的一个简单的写法,也就是说可以写成then(fn).catch(fn),相当于 then(fn).then(null, fn)。使用 catch 的写法比一般的写法更加清晰明确
1.8.5 all和race方法
    console.time();
    var p1 = new Promise(function(resolve) {
        setTimeout(function() {
            resolve("Hello");
        }, 3000);
    });

    var p2 = new Promise(function(resolve) {
        setTimeout(function() {
            resolve("world");
        }, 3000);
    })

    Promise.all([p1, p2]).then(function(result) {
        console.log(result);
        console.timeEnd();
    });
上面的例子模拟了传输两个数据需要不同的时长,虽然 p2 的速度比 p1 要快,但是 Promise.all 方法会按照数组里面的顺序将结果返回
日常开发中经常会遇到这样的需求,在不同的接口请求数据然后拼合成自己所需的数据,通常这些接口之间没有关联(例如不需要前一个接口的数据作为后一个接口的参数),这个时候 Promise.all 方法就可以派上用场了
还有一个和 Promise.all 相类似的方法 Promise.race,它同样接收一个数组,不同的是只要该数组中的 Promise 对象的状态发生变化(无论是 resolve 还是 reject)该方法都会返回
1.9 fetch网络请求

与ajax 请求的对比见下面的代码:

    

如果有需要可以按照上面的方式进行编写

二、ES6之Module系统 2.1 为什么要进行模块化?

可维护性的需要

可测性的需要

性能的需要

架构的需求

代码复用

多人协作的需要

2.2 导入导出

小编这里只说步骤:
第一步:在你需要导出的 js 文件中某个方法或对象时,前面加上 export 关键字
第二步: 在另一个js文件中导入你要导出的js文件,import 对象/方法 from ×××.js
第三步: 在html中引入入口js 文件,就是第二步中的另一个js文件。

阅读需要支付1元查看
<