ECMAScript6(day04)

Set WeakSet用法

1.1 什么set

SetES6给开发者带来的一种新的数据结构,你可以理解为值的集合。我们平时见到的数组Array也是一种数据结构,但是Set跟其他数据结构不同的地方就在于:它的值不会有重复项。

1.2 set基本用法

Set的用法:

1  var s = new Set();
2     console.log(s);
3     //打印结果:Set {}

Set本身是一个构造函数,你可以理解为一个类,使用的时候需要用new来创建一个实例。以上的案例就是这样创建出一个Set结构,我们打印出来看看,控制台输出:Set{ }

        它不是值的集合吗,那如果我们想给Set对象增加一些值成员,我们要怎么做?

        你可以这样:

 

1  var s = new Set([1,2,3]);
2     console.log(s);
3     //打印结果:Set {1, 2, 3}

 

案例中,用数组[ 1,2,3 ]作为参数传入,得到的变量sSet { 1, 2, 3 }

        除了上面的方法,你还可以这样

 

1 var s = new Set();
2     //使用add方法添加成员
3     s.add(1);
4     s.add(2);
5     s.add(3);
6     console.log(s);
7     //打印结果:Set {1, 2, 3}

 

如果你不想用数组作为参数来传值初始化变量s,你还可以通过Set 结构提供的add方法来添加方法,也是没问题的。

1.3成员值唯一

不过,为Set 结构添加成员值的时候,要注意一点是,set结构的成员值是没有重复的,每个值都是唯一的,如果人为地给它添加相同的成员值,会发生什么呢?

 

1 var s = new Set();
2     s.add(1);
3     s.add(1);
4     console.log(s);
5     //打印结果: Set {1}

 

 很明显,set结构会自动忽略相同的值,只会保留一个相同的值。

        Set 结构除了提供add方法用于添加成员以外,还提供了哪些方法和属性呢?

1.4 size属性

size属性:获取成员的个数。

1  let s = new Set([1,2,3,4]);
2     s.size; //结果:4

结果为4,跟我们预期一致,很简单。

 

1.5 delete属性

 delete( )方法:用户删除Set结构中的指定值,删除成功返回:true,删除失败返回:fasle

 

 1 //用数组作为参数初始化
 2     var s = new Set([1,2,3]);
 3     console.log(s);
 4     //打印结果:Set {1, 2, 3}
 5 
 6     //使用delete方法删除指定值
 7     s.delete(2);//结果:true
 8     s.delete(4);//结果:false
 9 
10     console.log(s);
11     //打印结果:Set {1, 3}

 

案例中,我们使用delete( )方法删除了指定值:2,结果返回true。删除指定值:4的时候,返回false,原因是变量s中找不到数字4

        Set结构的成员比较多,你觉得一个一个删除比较麻烦的时候,你可以用下面这个方法。

1.6clear方法

clear( )方法:清除所有成员。

 

1 //用数组作为参数初始化
2     var s = new Set([1,2,3]);
3     console.log(s);
4     //打印结果:Set {1, 2, 3}
5 
6     s.clear();
7     console.log(s);
8     //打印结果:Set {}

 

  上面的代码中,在使用clear( )方法之前和之后都打印了变量s的值,我们看到,clear( )方法使用之后,Set结构的成员都被清除了,一个不留。

1.7 has方法

has( )方法:判断set结构中是否含有指定的值。如果有,返回true;如果没有,返回fasle

 

1  //用数组作为参数初始化
2     var s = new Set([1,2,3]);
3     s.has(1);//结果:true
4     s.has(4);//结果:false

 

当判断变量s中是否含有数字1时,得到的结果是true,判断是否含有数字4的时候,得到的结果是false

1.8 enteries方法

entries( )方法:返回一个键值对的遍历器。

1  //用数组作为参数初始化
2     var s = new Set(['a','b','c']);
3     s.entries();
4     //结果:SetIterator {["a", "a"], ["b", "b"], ["c", "c"]}

注意得到的结果,成员值“a”对应的键值对是[“a”,”a”],也就是说:Set结构是键名和键值是同一个值。

1.9 keysvalues方法

 keys( )方法:返回键名的遍历器。

 values( )方法:返回键值的遍历器。

 

1 /用数组作为参数初始化
2     var s = new Set(['a','b','c']);
3 
4     s.keys();
5     //结果:SetIterator {"a", "b", "c"}
6 
7     s.values();
8     //结果:SetIterator {"a", "b", "c"}

 

我把两个函数放在一起演示,是因为上面entries()方法的使用告诉我们,Set结构的键名和键值是同一个值,那么我们就用Set结构提供的keys( )values()方法来检验一下。从得到的结果可以看出:两者确实一致

1 //用数组作为参数初始化
2     var s = new Set(['a','b','c']);
3     //用for...of遍历
4     for(let [i,v] of s.entries()){
5         console.log(i+' '+v);
6     }
7     //打印结果:a  a    
8     //         b  b   
9     //         c  c   

1.10 foreach方法

forEach( )方法:遍历每一个成员

 

1  //用数组作为参数初始化
2     var s = new Set(['a','b','c']);
3     //使用回调函数遍历每个成员
4     s.forEach(function(value,key){
5         console.log(value,key)
6     });
7     //打印结果:a  a
8     //         b  b
9     //         c  c

 

使用方式跟数组的forEach一样。当然,得到的valuekey的值是一样的。

1.11set用途之一

利用Set结构的成员值不能重复的特点,我们可以轻松的完成一些效果。

比如:有一天面试官要小菜实现数组去重的效果。

这个时候,小菜想起了ES6Set结构的特性,再也不需要去遍历数组的元素,然后再一个个对比了。 然后自信地写起下了代码:

 

1 //目标数组arr,要求去重
2     let arr = [1,2,2,3,4,4,4];
3     let s = new Set(arr);
4     //结果:Set {1,2,3,4}
5     let newArr = Array.from(s);
6     //结果:[1,2,3,4],完成去重

 

 上面的代码重点是一个含有重复元素的数组,作为参数,用于初始化一个Set实例对象,因为Set结构不会含有重复成员,就会自动忽略相同的元素,只保留一个相同的值。

1.12Weakset结构

讲到Set结构,就不能不讲WeakSet结构。SetWeakSet两者名字就很像,注定它们有很多一样的地方。

        WeakSet结构同样不会存储重复的值,不同的是,它的成员必须是对象类型的值。

 

1  //初始化一个WeakSet对象
2     let ws = new WeakSet([{"age":18}]);
3     //结果:WeakSet {Object {age: 18}}

 

我们初始化一个WeakSet对象,参数一个数组,数组的成员必须是对象类型的值{"age":18},否则就会报错。

 

1 //初始化一个WeakSet对象
2     let ws = new WeakSet([1,2]);
3     //结果:报错

 

以上的写法就会报错,因为数组的元素不是对象类型的,是数字1,2

        实际上,任何可遍历的对象,都可以作为WeakSet的初始化参数。比如:数组。

 

1  let arr1 = [1];
2     let arr2 = [2];
3     //初始化一个WeakSet对象,参数是数组类型
4     let ws = new WeakSet([arr1,arr2]);
5     //结果:WeakSet {Object {age: 18}}

 

同样,WeakSet结构也提供了add( ) 方法,delete( ) 方法,has( )方法给开发者使用,作用与用法跟Set结构完全一致。

 

        另一个不同点是:WeakSet 结构不可遍历。因为它的成员都是对象的弱引用,随时被回收机制回收,成员消失。所以WeakSet 结构不会有keys( )values( )entries( )forEach( )等方法和size属性。

MapWeakMap用法

什么是Map

介绍什么是Map,就不得不说起Object对象,我们都知道Object对象是键值对的集合

 

1 //Object对象
2     {"name":"前端君","gender":1}

 

ES5中的key键名的类型要求一定是字符串,当然,ES6已经允许属性名的类型是Symbol在,ES6 提供了Map结构给我们使用,它跟Object对象很像,但是不同的是,它的key键名的类型不再局限于字符串类型了,它可以是各种类型的值;可以说,它比Object对象更加灵活了,当然,也更加复杂了。

Map的基本用法

Map结构提供了一个构造函数给我们,我们使用的时候需要用new来创建实例:

 

1 let m = new Map();

 

 如果想要在创建实例的同时,初始化它的内容,我们可以给它传参,形式跟Set结构类型,都是需要用数组作为参数,我们来试试看看:

 

1  let m = new Map([
2             ["name","前端君"],
3             ["gender",1]
4     ]);
5     console.log(m);
6     //打印结果:Map {"name" => "前端君", "gender" => 1}

 

大家注意Map( )方法里面的参数,首先它是一个数组,而里面的内容也是由多个数组组成“name”前端君作为一个键值对,将它们装在一个数组里面,[“name”前端君”],另外一组键值对也一样:[“gender”1 ]。这就是初始化一个Map结构实例的基本写法。

        初始化成实例后,Map结构还提供了一些实例的属性和方法供我们实现对实例的操作。我们一起看看都有哪些属性和方法。

set方法

set( )方法作用:给实例设置一对键值对,返回map实例。

 

1  let m = new Map();
2 //set方法添加
3 //添加一个string类型的键名
4 m.set("name","前端君");  
5 //添加一个数字类型的键名
6 m.set(1,2);
7 console.log(m);
8 //打印结果:Map {"name" => "前端君", 1 => 2}

 

set方法的使用很简单,只需要给方法传入keyvalue作为键名和键值即可。注意:第三行代码中,我们传入的key是数字1,这就证明了,Map结构确实可以存储非字符串类型的键名,当然你还可以设置更多其它类型的键名,比如:

 

 1  //数组类型的键名
 2 m.set([1],2);
 3 //对象类型的键名
 4 m.set({"name":"Zhangsan"},2);
 5 //布尔类型的键名
 6 m.set(true,2);
 7 //Symbol类型的键名
 8 m.set(Symbol('name'),2);
 9 //null为键名
10 m.set(null,2);
11 //undefined为键名
12 m.set(undefined,2);

 

  以上6种类型值都可以作为键名,可以成功添加键值对,没毛病。

        使用set方法的时候有一点需要注意,如果你设置一个已经存在的键名,那么后面的键值会覆盖前面的键值。我们演示一下:

 

1 let m = new Map();
2 m.set("name","前端君");
3 console.log(m);
4 //结果:Map {"name" => "前端君"}
5 //再次设置name的值
6 m.set("name","隔壁老王");
7 console.log(m);
8 //结果:Map {"name" => "隔壁老王"}

 

上面的案例,我们第一次把name的值设置为前端君,当再次使用set方法设置name的值的时候,后者成功覆盖了前者的值,从此“前端君” 变 “隔壁老王”。

get方法

get( )方法作用:获取指定键名的键值,返回键值。

1 let m = new Map([["name","前端君"]]);
2 m.get("name");//结果:前端君
3 m.get("gender");//结果:undefined

   get方法使用也很简单,只需要指定键名即可。获取存在对应的键值,如果键值对存在,就会返回键值;否则,返回undefined,这个也很好理解。

 

delete方法

delete( )方法作用:删除指定的键值对,删除成功返回:true,否则返回:false

 

1 let m = new Map();
2 m.set("name","前端君");
3 //结果:Map {"name" => "前端君"}
4 m.delete("name");//结果:true
5 m.delete("gender");//结果:false

 

我们使用delete方法,删除“name”的时候成功,返回了true。删除“gender”的时候,由于Map结构中不存在键名:“gender”,所以删除失败,返回false

clear方法

Set结构一样,Map结构也提供了clear( )方法,让你一次性删除所有键值对。

 

1 let m = new Map();
2 m.set("name","前端君");
3 m.set("gender",1);
4 m.clear(); 
5 console.log(m);
6 //打印结果:Map {}

 

使用clear方法后,我们再打印一下变量m,发现什么都没有,一个空的Map结构,说明clear方法起作用了。

has方法

has( )方法作用:判断Map实例内是否含有指定的键值对,有就返回:true,否则返回:false

 

1 let m = new Map();
2 m.set("name","前端君"); 
3 m.has('name');//结果:true
4 m.has('age');//结果:false

 

   Map实例中含有键名:name,就返回了true,键名age不存在,就返回false。好理解吧,比较简单。

entries方法

entries( )方法作用:返回实例的键值对遍历器。

 

1 let m = new Map([
2     ["name","前端君"],
3     ["age",25]
4 ]);
5 for(let [key,value] of m.entries()){
6     console.log(key+'  '+value);
7 }
8 //打印结果:name  前端君
9 //              age  25

 

案例中的 m.entries( ) 返回键值对的遍历器,使用了for...of来遍历这个遍历器,得到的值分别赋值到keyvalue,然后控制台分别输出它们。

 

keysvalues方法

keys( )方法:返回实例所有键名的遍历器。

values( ) 方法:返回实例所有键值的遍历器。

既然都是遍历器,那就用for...of把它们遍历出来吧:

 

 1 let m = new Map([
 2     ["name","前端君"],
 3     ["age",25]
 4 ]);
 5 //使用keys方法获取键名
 6 for(let key of m.keys()){
 7     console.log(key);
 8 }
 9 //打印结果:name
10 //age
11 //使用values方法获取键值
12 for(let value of m.values()){
13     console.log(value);
14 }
15 //打印结果:前端君
16 //                 25

 

keys方法和values方法的使用方式一致,只是返回的结果不同。

forEach方法

除了使用以上三个方法实现遍历以外,我们还可以使用forEach遍历每一个键值对:

 

1  let m = new Map([
2     ["name","前端君"],
3     ["age",25]
4 ]);    
5 m.forEach(function(value,key){
6     console.log(key+':'+value);
7 });
8     //打印结果:name:前端君
9     //                 age:25

 

 forEach方法接收一个匿名函数,给匿名函数传参valuekey,分别是Map实例的键名和键值,这个方法的使用相信大家一定不会陌生。

 

size属性

其中一个常用的属性就是size:获取实例的成员数。

 

1 let m = new Map();
2     m.set(1,3);
3     m.set('1','3');
4     m.size;//结果:2

 

使用set方法给实例m添加了两个键值对成员,所以实例的 size为:2

什么WeakMap

WeakMap结构和Map结构很类似,不同点在于WeakMap结构的键名只支持引用类型的数据。哪些是引用类型的值呢?比如:数组,对象,函数。

关于什么是引用类型,其中涉及到了传址和传值的区别,还记得装修工张师傅和王师傅的例子吗?

WeakMap的基本用法

WeakMap结构的使用方式和Map结构一样:

 

1  let wm = new WeakMap();

 

 两者都是使用new来创建实例。如果添加键值对的话,我们同样是使用set方法,不过键名的类型必须要求是引用类型的值,我们来看看:

 

 1 let wm = new WeakMap();
 2 //数组类型的键名
 3 wm.set([1],2);
 4 //对象类型的键名
 5 wm.set({'name':'Zhangsan'},2);
 6 //函数类型的键名
 7 function fn(){};
 8 wm.set(fn,2);
 9 console.log(wm);
10 //打印:WeakMap {
11         [1] => 2, 
12         Object {name: "Zhangsan"} => 2, 
13         function => 2
14         }

 

从打印结果可以看出,以上类型的键名都可以成功添加到WeakMap实例中。

WeakMapMap的区别?

如果是普通的值类型则不允许。比如:字符串,数字,nullundefined,布尔类型。而Map结构是允许的,这就是两者的不同之处,谨记。

 

        Map一样,WeakMap也拥有gethasdelete方法,用法和用途都一样。不同地方在于,WeakMap不支持clear方法,不支持遍历,也就没有了keysvaluesentriesforEach4个方法,也没有属性size

 

        理由跟WeakSet结构一样:键名中的引用类型是弱引用,你永远不知道这个引用对象什么时候会被垃圾回收机制回收了,如果这个引用类型的值被垃圾机制回收了,WeakMap实例中的对应键值对也会消失。

 

3、ES6Promise对象

Promise设计初衷

你需要用ajax进行多次请求,而且,每次请求都依赖上一次请求返回的数据来作为参数,然后继续发出请求,你把代码写成了这样:

 

 1  //------请求A 开始---------
 2     $.ajax({
 3         success:function(res1){
 4             //------请求B 开始----
 5             $.ajax({
 6                 success:function(res2){
 7                     //----请求C 开始---
 8                     $.ajax({
 9                         success:function(res3){
10                         }
11                     });
12                     //---请求C 结束---
13                 }    
14             });
15             //------请求B 结束-----
16         }
17     });
18     //------请求A 结束---------

 

上面的案例,假设请求C需要依赖请求B返回的数据,所以,C只能放在Bsuccess函数内;B需要依赖A请求得到的数据作为参数,所以,B只能放在Asuccess函数内;也就是:请求A包含着请求B,请求B又包含了请求C

就这样,请求顺序为:请求A -> 请求B -> 请求C,最后你也能顺利的完成了任务。

传统写法的缺点:

1.  如果存在多个请求操作层层依赖的话,那么以上的嵌套就有可能不止三层那么少了,加上每一层还会有复杂的业务逻辑处理,代码可读性也越来越差,不直观,调试起来也不方便。如果多人开发的时候没有足够的沟通协商,大家的代码风格不一致的话,更是雪上加霜,给后面的维护带来极大的不便。

 

2.  如果请求C的需要依赖AB的结果,但是请求AB缺互相独立,没有依赖关系,以上的实现方式,就使得B必须得到A请求完成后才可以执行,无疑是消耗了更多的等待时间。

        既然使用这种回调函数层层嵌套(又称:回调地狱)的形式存在缺点,ES6想了办法治它,所以就有了Promise的出现了。

那么我们就知道了:Promise对象能使我们更合理、更规范地进行处理异步操作

 

Promise基本用法

我们就看看它的基本用法:promise 承诺

ECMAScript6(day04)_第1张图片

 

 Promise对象是全局对象,你也可以理解为一个类,创建Promise实例的时候,要有那个new关键字。参数是一个匿名函数,其中有两个参数:resolve(解决)reject(拒绝),两个函数均为方法resolve方法用于处理异步操作成功后业务;reject方法用于操作异步操作失败后的业务。

Promise的三种状态

Promise对象有三种状态:

1.pending:刚刚创建一个Promise实例的时候,表示初始状态;

2.fulfilledresolve方法调用的时候,表示操作成功;

3.rejectedreject方法调用的时候,表示操作失败;

状态只能从 初始化 -> 成功  或者  初始化 -> 失败,不能逆向转换,也不能在成功fulfilled

和失败rejected之间转换。

 

 1 let pro = new Promise(function(resolve,reject){
 2         //实例化后状态:pending
 3         if('操作成功'){
 4             resolve();
 5             //resolve方法调用,状态为:fulfilled
 6         }else{
 7             reject();
 8             //reject方法调用,状态为:rejected
 9         }
10     });

 

上面的注释,讲清楚了一个Promise实例的状态改变情况。

        初始化实例后,对象的状态就变成了pending;当resolve方法被调用的时候,状态就变成了:成功fulfilled;当reject方法被调用的时候,状态就会有pending变成失败rejected

Then方法

了解了Promise的创建和状态,我们来学习一个最重要的实例方法:then( )方法。

  then( )方法:用于绑定处理操作后的处理程序

1  pro.then(function (res) {
2         //操作成功的处理程序
3     },function (error) {
4         //操作失败的处理程序
5     });

参数是两个函数,第一个用于处理操作成功后的业务,第二个用于处理操作异常后的业务。

Catch方法

对于操作异常的程序,Promise专门提供了一个实例方法来处理:catch( )方法。

 

1 pro.catch(function (error) {
2         //操作失败的处理程序
3     });

 

 catch只接受一个参数,用于处理操作异常后的业务。

        综合上面的两个方法,大家都建议将then方法用于处理操作成功,catch方法用于处理操作异常,也就是:

 

1 pro.then(function (res) {
2         //操作成功的处理程序
3     }).catch(function (error) {
4         //操作失败的处理程序
5     });

 

之所以能够使用链式调用,是因为then方法和catch方法调用后,都会返回promise对象。

        讲了那么多,如果你之前一点都没接触过Promise的话,现在一定很懵逼,没关系,下面我们用一个案例来串联前面的知识点,演示一下,认真阅读注释:

 

 1  //用new关键字创建一个Promise实例
 2     let pro = new Promise(function(resolve,reject){
 3         //假设condition的值为true
 4         let condition = true;
 5 
 6         if(condition){
 7             //调用操作成功方法
 8             resolve('操作成功');    
 9             //状态:pending->fulfilled
10         }else{
11             //调用操作异常方法
12             reject('操作异常');
13             //状态:pending->rejected
14         }
15     });
16 
17     //用then处理操作成功,catch处理操作异常
18     pro.then(function (res) {
19 
20         //操作成功的处理程序
21         console.log(res)
22 
23     }).catch(function (error) {
24 
25         //操作失败的处理程序
26         console.log(error)
27 
28     });
29     //控制台输出:操作成功

 

上面案例的注释十分详细,串联起了上面介绍的所有知识点:创建实例,状态转换,then方法和catch方法的使用

 

        由于我们设置了变量condition的值为true,所以执行后控制台输出的结果是:“操作成功”。

案例

我们看看下面的案例:

 1 let pro = new Promise(function(resolve,reject){
 2         if(true){
 3             //调用操作成功方法
 4             resolve('操作成功');
 5         }else{
 6             //调用操作异常方法
 7             reject('操作异常');
 8         }
 9     });
10 
11     //用then处理操作成功,catch处理操作异常
12     pro.then(requestA)
13         .then(requestB)
14         .then(requestC)
15         .catch(requestError);
16 
17     function requestA(){
18         console.log('请求A成功');
19         return '请求B,下一个就是你了';
20     }
21     function requestB(res){
22         console.log('上一步的结果:'+res);
23         console.log('请求B成功');
24         return '请求C,下一个就是你了';
25     }
26     function requestC(res){
27         console.log('上一步的结果:'+res);
28         console.log('请求C成功');
29     }
30     function requestError(){
31         console.log('请求失败');
32     }
33 
34     //打印结果:
35     //请求A成功
36     //上一步的结果:请求B,下一个就是你了
37     //请求B成功
38     //上一步的结果:请求C,下一个就是你了
39     //请求C成功

案例中,先是创建一个实例,还声明了4个函数,其中三个是分别代表着请求A,请求B,请求C有了then方法,三个请求操作再也不用层层嵌套了。我们使用then方法,按照调用顺序,很直观地完成了三个操作的绑定,并且,如果请求B依赖于请求A的结果,那么,可以在请求A的程序用使用return语句把需要的数据作为参数,传递给下一个请求,案例中我们就是使用return实现传递参数给下一步操作的。

ECMAScript6(day04)_第2张图片

 

Promise.all方法

Promise.all( )方法:接受一个数组作为参数,数组的元素是Promise实例对象,当参数中的实例对象的状态都为fulfilled时,Promise.all( )才会有返回。

 

 1 //创建实例pro1
 2     let pro1 = new Promise(function(resolve){
 3         setTimeout(function () {
 4             resolve('实例1操作成功');
 5         },5000);
 6     });
 7     
 8     //创建实例pro2
 9     let pro2 = new Promise(function(resolve){
10         setTimeout(function () {
11             resolve('实例2操作成功');
12         },1000);
13     });
14 
15     
16     Promise.all([pro1,pro2]).then(function(result){
17         console.log(result);
18     });
19     //打印结果:["实例1操作成功", "实例2操作成功"]

 

上述案例,我们创建了两个Promise实例:pro1pro2,我们注意两个setTimeout的第二个参数,分别是5000毫秒和1000毫秒,当我们调用Promise.all( )方法的时候,会延迟到5秒才控制台会输出结果。

        因为1000毫秒以后,实例pro2进入了成功fulfilled状态;此时,Promise.all( )还不会有所行动,因为实例pro1还没有进入成功fulfilled状态;等到了5000毫秒以后,实例pro1也进入了成功fulfilled状态,Promise.all( )才会进入then方法,然后在控制台输出:["实例1操作成功","实例2操作成功"]

        这个方法有什么用呢?一般这样的场景:我们执行某个操作,这个操作需要得到需要多个接口请求回来的数据来支持,但是这些接口请求之前互不依赖,不需要层层嵌套。这种情况下就适合使用Promise.all( )方法,因为它会得到所有接口都请求成功了,才会进行操作。

 

Promise.race方法

Promise.race()方法:它的参数要求跟Promise.all( )方法一样,不同的是,它参数中的promise实例,只要有一个状态发生变化(不管是成功fulfilled还是异常rejected),它就会有返回,其他实例中再发生变化,它也不管了。

 1  //初始化实例pro1
 2     let pro1 = new Promise(function(resolve){
 3         setTimeout(function () {
 4             resolve('实例1操作成功');
 5         },4000);
 6     });
 7 
 8     //初始化实例pro2
 9     let pro2 = new Promise(function(resolve,reject){
10         setTimeout(function () {
11             reject('实例2操作失败');
12         },2000);
13     });
14 
15     Promise.race([pro2,pro1]).then(function(result){
16         console.log(result);
17     }).catch(function(error){
18         console.log(error);
19     });
20     //打印结果:实例2操作失败

同样是两个实例,实例pro1不变,不同的是实例pro2,这次我们调用的是失败函数reject

        由于pro2实例中2000毫秒之后就执行reject方法,早于实例pro14000毫秒,所以最后输出的是:实例2操作失败。

        以上就是对Promise对象的内容讲解,上面提到了一个概念:回调地狱;指的是过多地使用回调函数嵌套,使得调试和维护起来极其的不便。

类基本用法

4.1  的属性和方法

声明一个类的写法:

ECMAScript6(day04)_第3张图片

代码很简短,我们通过关键字class来声明一个名字叫Animal,可以看到类里面(花括号 {}里面)有一个叫constructor构造、建造方法,它就是构造方法,构造方法里面的this,指向的是该类实例化后的对象,这就是实现了一个类的声明

 

        其中,构造方法constructor是一个类必须要有的方法,默认返回实例对象;创建类的实例对象的时候,会调用此方法来初始化实例对象。如果你没有编写constructor方法,执行的时候也会被加上一个默认的空的constructor方法。

 

4.2的实例化对象

了解了类的声明和constructor构造函数的特点,我们下面来了解如何给类添加属性和方法。

ECMAScript6(day04)_第4张图片

 

我们把类名后面的括号{ }里面的内容称之为类体,我们会在类体内来编写类的属性和方法。上面的案例中,类体内有2个方法:constructor( )getName()

        其中constructor方法是构造方法,在实例化一个类的时候被调用constructor方法是必须的,也是唯一的,一个类体不能含有多个constructor构造方法。我们可以在方法里面自定义一些对象的属性,比如案例中的name属性。

 此外,我们还自定义了一个getName( )方法,它属于类的实例方法,实例化后对象可以调用此方法。

4.3  的静态方法

掌握了类的属性和方法的写法,接下来,我们学习如何创建对象和使用对象的实例方法:

ECMAScript6(day04)_第5张图片

 

还是同一个类Animal,我们通过new来创建了实例对象dog,构造方法会把传进去的参数“dog”通过this.name赋值给对象的name属性,所以dogname属性为“dog”,对象dog还可以调用自己的实例方法getName( ),结果返回:“This is a dog”

        实例对象的创建有几个要注意的事项:

1.  必须使用new创建字来创建类的实例对象

2.先声明定义类,再创建实例,否则会报错

 

1.1  的继承

说到类class,就不得不说类的继承,ES6使用extends关键字来实现子类继承父类,我们来演示一下:

ECMAScript6(day04)_第6张图片

 

上面的案例中,我们定义两个类,Animal类作为父类,Dog类作为子类,然后通过关键字extends来实现继承,此外,我们还注意到一个关键字super,它相当于是父类中的this

 

 我们可以用super来引用父类,访问父类的方法,我们来演示一下:

ECMAScript6(day04)_第7张图片

 

ECMAScript6(day04)_第8张图片

ECMAScript6(day04)_第9张图片

在父类中,我们定义了say方法,想要在子类中调用父类的say方法的话,我们使用super.say( )即可实现。

        使用super有几个要注意的事项:

1.  类必须在constructor方法中调用super方法

2.  调用super( ),才可以使用this,否则报错

 以上就是关于类继承的介绍,重点在于关键字extendssuper,尤其是super的理解和使用,大家需要理解透彻。

 

5Module模块

5.1  模块化的初衷

现在的web系统越来越庞大、复杂,需要团队分工,多人协作,大型系统的javascript文件经常存在复杂的依赖关系,后期的维护成本会越来越高。

 

 JavaScript模块化正式为了解决这一需求而诞生。

 竟然模块化这么重要,我们看看ES6module模块是什么实现的?

  Ps目前还没有浏览器支持ES6module模块

 假设现在有两个js文件,分别是module-A.jsmodule-B.js,我们把它们视为两个模块。带着这个假设,下面我们来学习module模块的几个概念以及它们的含义。

5.2  模块Module

模块Module一个模块,就是一个对其他模块暴露自己的属性或者方法的文件。

在这里,我们会把module-A.jsmodule-B.js分别当作两个模块(moduleA模块和moduleB模块)来对待和处理。用这两个模块来演示如何暴露一个模块的属性或方法。

 

5.3  导出Export

导出Export作为一个模块,它可以选择性地给其他模块暴露(提供)自己的属性和方法,供其他模块使用。

 

5.4  导入Import

导入Import作为一个模块,可以根据需要,引入其他模块的提供的属性或者方法,供自己模块使用。

 

5.5  模块化的实现

带着这三个概念,我们来演示一下它们的基本用法:

moduleB模块代码:

ECMAScript6(day04)_第10张图片

 

模块B我们使用关键字export关键字,对外暴露了一个属性:name的值为:字符串前端君。一个关键字,一句代码就实现了,是不是很简单。

模块B演示了导出,接下来我们用模块A来演示如何导入。

moduleA模块代码:

ECMAScript6(day04)_第11张图片

 

模块A我们使用关键字import导入了模块Bname属性,并且赋值给变量name。关键字from的作用是指定你想要引入的模块,我们这里指定的是module-B.js文件,也就是上面的模块B。打印结果:前端君正是模块B的对外暴露的属性。

 

5.6  批量导出

对于模块B,如果你想导出(暴露)多个属性和方法的话,你可以这样实现:

ECMAScript6(day04)_第12张图片 

上面,我们定义了2个属性和1个方法,最后用一个对象实现将它们批量导出。我们更推荐的是使用这种方法实现导出,因为当对外暴露的属性和方法较多的时候,这种方法可以更直观地看出当前模块暴露了哪些变量。

 

        而对于这种批量导出,我们导入的时候怎么对应上呢?

ECMAScript6(day04)_第13张图片

 

同样,我们使用多个同名变量就可以获取对应的属性和方法,变量名字必须跟导出的一致才能准确获取,位置顺序无要求。

5.7  重命名导出的变量

也许你突发奇想,想给导入的变量换一个名字的话,你可以这样做:

ECMAScript6(day04)_第14张图片

 

使用关键字as,可以实现给变量name更换名字为myname。最后正确输出myname的值:“前端君”。

 

5.8  整体导入

我们还可以使用星号*实现整体导入:

ECMAScript6(day04)_第15张图片

 

使用星号符*将模块B提供的所有属性和方法整体导入赋值给变量obj,我们可以点运算符来获取它的属性和方法。

5.9  默认导出

默认导出,每个模块支持我们导出一个没有名字的变量,我们使用关键语句export default来实现:

ECMAScript6(day04)_第16张图片

 

 我们使用export default关键字对外导出一个匿名函数,导入这个模块的时候,可以为这个匿名函数取任意的名字,我们试一下导入上面那个匿名函数:

ECMAScript6(day04)_第17张图片

 

同样是使用import关键字导入模块B,但是这次不需要使用大括号{ }。我们使用新的名字:sayDefault来代替导入的匿名函数,最后调用一下,打印结果正是模块B默认导出的匿名函数的执行效果。

 

5.10  注意事项

1.  声明的变量,对外都是只读的

ECMAScript6(day04)_第18张图片

 

上面的代码片段包含了2个模块,其中,模块B导出了字符串变量name,模块A导出变量name之后试图修改它的值,结果报错。

   但是,如果模块B导出的是对象类型的值,就可修改。

ECMAScript6(day04)_第19张图片

 

 上面的代码片段包含了2个模块,模块B导出了对象person,模块A导入后,对其属性name进行修改,结果修改成功,这一点大家要注意,并不是所有导出的变量都不可修改,对象类型就可修改。

2.  导入不存在的变量,值为undefined

ECMAScript6(day04)_第20张图片

模块A想导入的变量height,在模块B中并没有提供,但这不会抛出异常,只是height的值为undefined

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 pro.then(function (res) {

        //操作成功的处理程序
    },function (error) {
        //操作失败的处理程序
    });

你可能感兴趣的:(ECMAScript6(day04))