ECMAScript6(day04)

ECMAScript6(day04)

1、Set 和 WeakSet用法
1.1什么是set
Set是ES6给开发者带来的一种新的数据结构,你可以理解为值的集合。我们平时见到的数组Array也是一种数据结构,但是Set跟其他数据结构不同的地方就在于:它的值不会有重复项。
1.2set的基本用法
一、
var s = new Set();
console.log(s);
//打印结果:Set {}
二、
var s = new Set([1,2,3]);
console.log(s);
//打印结果:Set {1, 2, 3}
三、
var s = new Set();
//使用add方法添加成员
s.add(1);
s.add(2);
s.add(3);
console.log(s);
//打印结果:Set {1, 2, 3}

1.3成员值唯一
不过,为Set 结构添加成员值的时候,要注意一点是,set结构的成员值是没有重复的,每个值都是唯一的
var s = new Set();
   s.add(1);
   s.add(1);
   console.log(s);
   //打印结果: Set {1}

1.1 size属性

size属性:获取成员的个数。
 let s = new Set([1,2,3,4]);
   s.size; //结果:4

1.5delete属性
delete( )方法:用户删除Set结构中的指定值,删除成功返回:true,删除失败返回:fasle。
//用数组作为参数初始化
   var s = new Set([1,2,3]);
   console.log(s);
   //打印结果:Set {1, 2, 3}

   //使用delete方法删除指定值
   s.delete(2);//结果:true
   s.delete(4);//结果:false

   console.log(s);
   //打印结果:Set {1, 3}
1.6clear方法
clear( )方法:清除所有成员。
//用数组作为参数初始化
   var s = new Set([1,2,3]);
   console.log(s);
   //打印结果:Set {1, 2, 3}

   s.clear();
   console.log(s);
   //打印结果:Set {}
1.7has方法
has( )方法:判断set结构中是否含有指定的值。如果有,返回true;如果没有,返回fasle。
 //用数组作为参数初始化
   var s = new Set([1,2,3]);
   s.has(1);//结果:true
   s.has(4);//结果:false

当判断变量s中是否含有数字1时,得到的结果是true,判断是否含有数字4的时候,得到的结果是false。
1.8enteries方法
entries( )方法:返回一个键值对的遍历器。
 //用数组作为参数初始化
   var s = new Set(['a','b','c']);
   s.entries();
   //结果:SetIterator {["a", "a"], ["b", "b"], ["c", "c"]}
 
注意得到的结果,成员值“a”对应的键值对是[“a”,”a”],也就是说:Set结构是键名和键值是同一个值。
1.9keys和values方法
 keys( )方法:返回键名的遍历器。
 values( )方法:返回键值的遍历器。
//用数组作为参数初始化
   var s = new Set(['a','b','c']);

   s.keys();
   //结果:SetIterator {"a", "b", "c"}

   s.values();
   //结果:SetIterator {"a", "b", "c"}


我把两个函数放在一起演示,是因为上面entries()方法的使用告诉我们,Set结构的键名和键值是同一个值,那么我们就用Set结构提供的keys( )和values()方法来检验一下。从得到的结果可以看出:两者确实一致。
//用数组作为参数初始化
   var s = new Set(['a','b','c']);
   //用for...of遍历
   for(let [i,v] of s.entries()){
        console.log(i+' '+v);
   }
   //打印结果:a  a    
   //         b  b  
   //         c  c   
1.10foreach方法
forEach( )方法:遍历每一个成员。
 //用数组作为参数初始化
   var s = new Set(['a','b','c']);
   //使用回调函数遍历每个成员
   s.forEach(function(value,key){
        console.log(value,key)
   });
   //打印结果:a  a
   //         b  b
   //         c  c

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

1.1 set用途之一

//目标数组arr,要求去重
   let arr = [1,2,2,3,4,4,4];
   let s = new Set(arr);
   //结果:Set {1,2,3,4}
   let newArr = Array.from(s);
   //结果:[1,2,3,4],完成去重
 上面的代码重点是一个含有重复元素的数组,作为参数,用于初始化一个Set实例对象,因为Set结构不会含有重复成员,就会自动忽略相同的元素,只保留一个相同的值。
1.12Weakset结构
讲到Set结构,就不能不讲WeakSet结构。Set和WeakSet两者名字就很像,注定它们有很多一样的地方。
        WeakSet结构同样不会存储重复的值,不同的是,它的成员必须是对象类型的值。
 //初始化一个WeakSet对象
   let ws = new WeakSet([{"age":18}]);
   //结果:WeakSet {Object {age: 18}}
  我们初始化一个WeakSet对象,参数一个数组,数组的成员必须是对象类型的值{"age":18},否则就会报错。
 //初始化一个WeakSet对象
   let ws = new WeakSet([1,2]);
   //结果:报错
   以上的写法就会报错,因为数组的元素不是对象类型的,是数字1,2。
        实际上,任何可遍历的对象,都可以作为WeakSet的初始化参数。比如:数组。
 let arr1 = [1];
   let arr2 = [2];
   //初始化一个WeakSet对象,参数是数组类型
   let ws = new WeakSet([arr1,arr2]);
   //结果:WeakSet {Object {age: 18}}
同样,WeakSet结构也提供了add( ) 方法,delete( ) 方法,has( )方法给开发者使用,作用与用法跟Set结构完全一致。

2、Map和WeakMap用法

介绍什么是Map,就不得不说起Object对象,我们都知道Object对象是键值对的集合:
 //Object对象
   {"name":"前端君","gender":1}

Map的基本用法
Map结构提供了一个构造函数给我们,我们使用的时候需要用new来创建实例:
   let m = new Map();
 如果想要在创建实例的同时,初始化它的内容,我们可以给它传参,形式跟Set结构类型,都是需要用数组作为参数,我们来试试看看:
 let m = new Map([
           ["name","前端君"],
           ["gender",1]
   ]);
   console.log(m);
   //打印结果:Map {"name" => "前端君", "gender" => 1}

set方法
set( )方法作用:给实例设置一对键值对,返回map实例。
 let m = new Map();
//set方法添加
//添加一个string类型的键名
m.set("name","前端君");  
//添加一个数字类型的键名
m.set(1,2);
console.log(m);
//打印结果:Map {"name" => "前端君", 1 => 2}

 //数组类型的键名
m.set([1],2);
//对象类型的键名
m.set({"name":"Zhangsan"},2);
//布尔类型的键名
m.set(true,2);
//Symbol类型的键名
m.set(Symbol('name'),2);
//null为键名
m.set(null,2);
//undefined为键名
m.set(undefined,2);

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

get方法

get( )方法作用:获取指定键名的键值,返回键值。
let m = new Map([["name","前端君"]]);
m.get("name");//结果:前端君
m.get("gender");//结果:undefined
   get方法使用也很简单,只需要指定键名即可。获取存在对应的键值,如果键值对存在,就会返回键值;否则,返回undefined,这个也很好理解。

delete方法
delete( )方法作用:删除指定的键值对,删除成功返回:true,否则返回:false。
let m = new Map();
m.set("name","前端君");
//结果:Map {"name" => "前端君"}
m.delete("name");//结果:true
m.delete("gender");//结果:false
  我们使用delete方法,删除“name”的时候成功,返回了true。删除“gender”的时候,由于Map结构中不存在键名:“gender”,所以删除失败,返回false。
clear方法
跟Set结构一样,Map结构也提供了clear( )方法,让你一次性删除所有键值对。
let m = new Map();
m.set("name","前端君");
m.set("gender",1);
m.clear(); 
console.log(m);
//打印结果:Map {}
使用clear方法后,我们再打印一下变量m,发现什么都没有,一个空的Map结构,说明clear方法起作用了。
has方法
has( )方法作用:判断Map实例内是否含有指定的键值对,有就返回:true,否则返回:false。
let m = new Map();
m.set("name","前端君"); 
m.has('name');//结果:true
m.has('age');//结果:false
   Map实例中含有键名:name,就返回了true,键名age不存在,就返回false。好理解吧,比较简单。
entries方法
entries( )方法作用:返回实例的键值对遍历器。
let m = new Map([
   ["name","前端君"],
   ["age",25]
]);
for(let [key,value] of m.entries()){
    console.log(key+'  '+value);
}
//打印结果:name  前端君
//              age  25
案例中的 m.entries( ) 返回键值对的遍历器,使用了for...of来遍历这个遍历器,得到的值分别赋值到key和value,然后控制台分别输出它们。

keys和values方法
keys( )方法:返回实例所有键名的遍历器。
values( ) 方法:返回实例所有键值的遍历器。
既然都是遍历器,那就用for...of把它们遍历出来吧:
let m = new Map([
   ["name","前端君"],
   ["age",25]
]);
//使用keys方法获取键名
for(let key of m.keys()){
    console.log(key);
}
//打印结果:name
//age
//使用values方法获取键值
for(let value of m.values()){
    console.log(value);
}
//打印结果:前端君
//                 25
keys方法和values方法的使用方式一致,只是返回的结果不同。
forEach方法
除了使用以上三个方法实现遍历以外,我们还可以使用forEach遍历每一个键值对:
 let m = new Map([
   ["name","前端君"],
   ["age",25]
]);    
m.forEach(function(value,key){
console.log(key+':'+value);
});
   //打印结果:name:前端君
   //                 age:25
 forEach方法接收一个匿名函数,给匿名函数传参value和key,分别是Map实例的键名和键值,这个方法的使用相信大家一定不会陌生。

size属性
其中一个常用的属性就是size:获取实例的成员数。
let m = new Map();
   m.set(1,3);
   m.set('1','3');
   m.size;//结果:2

WeakMap的基本用法
WeakMap结构的使用方式和Map结构一样:
 let wm = new WeakMap();
 两者都是使用new来创建实例。如果添加键值对的话,我们同样是使用set方法,不过键名的类型必须要求是引用类型的值,我们来看看:
let wm = new WeakMap();
//数组类型的键名
wm.set([1],2);
//对象类型的键名
wm.set({'name':'Zhangsan'},2);
//函数类型的键名
function fn(){};
wm.set(fn,2);
console.log(wm);
//打印:WeakMap {
       [1] => 2,
       Object {name: "Zhangsan"} => 2,
       function => 2
       }
  从打印结果可以看出,以上类型的键名都可以成功添加到WeakMap实例中。
WeakMap与Map的区别?
  1.如果是普通的值类型则不允许。比如:字符串,数字,null,undefined,布尔类型。而Map结构是允许的,这就是两者的不同之处,谨记。

        2.跟Map一样,WeakMap也拥有get、has、delete方法,用法和用途都一样。不同地方在于,WeakMap不支持clear方法,不支持遍历,也就没有了keys、values、entries、forEach这4个方法,也没有属性size。

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

3、ES6的Promise对象

Promise设计初衷
你需要用ajax进行多次请求,而且,每次请求都依赖上一次请求返回的数据来作为参数,然后继续发出请求,你把代码写成了这样:
 //------请求A 开始---------
   $.ajax({
        success:function(res1){
            //------请求B 开始----
            $.ajax({
                success:function(res2){
                    //----请求C 开始---
                    $.ajax({
                        success:function(res3){
                        }
                    });
                    //---请求C 结束---
                }    
            });
            //------请求B 结束-----
        }
   });
   //------请求A 结束---------

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

2.  如果请求C的需要依赖A和B的结果,但是请求A和B缺互相独立,没有依赖关系,以上的实现方式,就使得B必须得到A请求完成后才可以执行,无疑是消耗了更多的等待时间。
        既然使用这种回调函数层层嵌套(又称:回调地狱)的形式存在缺点,ES6想了办法治它,所以就有了Promise的出现了。
那么我们就知道了:Promise对象能使我们更合理、更规范地进行处理异步操作。

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

 Promise对象是全局对象,你也可以理解为一个类,创建Promise实例的时候,要有那个new关键字。参数是一个匿名函数,其中有两个参数:resolve(解决)和reject(拒绝),两个函数均为方法。resolve方法用于处理异步操作成功后业务;reject方法用于操作异步操作失败后的业务。
Promise的三种状态
Promise对象有三种状态:
1.pending:刚刚创建一个Promise实例的时候,表示初始状态;
2.fulfilled:resolve方法调用的时候,表示操作成功;
3.rejected:reject方法调用的时候,表示操作失败;
状态只能从 初始化 -> 成功  或者  初始化 -> 失败,不能逆向转换,也不能在成功fulfilled
和失败rejected之间转换。
let pro = new Promise(function(resolve,reject){
        //实例化后状态:pending
        if('操作成功'){
            resolve();
            //resolve方法调用,状态为:fulfilled
        }else{
            reject();
            //reject方法调用,状态为:rejected
        }
   });
上面的注释,讲清楚了一个Promise实例的状态改变情况。
        初始化实例后,对象的状态就变成了pending;当resolve方法被调用的时候,状态就变成了:成功fulfilled;当reject方法被调用的时候,状态就会有pending变成失败rejected。

Then方法
了解了Promise的创建和状态,我们来学习一个最重要的实例方法:then( )方法。
  then( )方法:用于绑定处理操作后的处理程序。
 pro.then(function (res) {
        //操作成功的处理程序
   },function (error) {
        //操作失败的处理程序
   });
参数是两个函数,第一个用于处理操作成功后的业务,第二个用于处理操作异常后的业务。
Catch方法
对于操作异常的程序,Promise专门提供了一个实例方法来处理:catch( )方法。
 pro.catch(function (error) {
        //操作失败的处理程序
   });
 catch只接受一个参数,用于处理操作异常后的业务。
        综合上面的两个方法,大家都建议将then方法用于处理操作成功,catch方法用于处理操作异常,也就是:
pro.then(function (res) {
        //操作成功的处理程序
   }).catch(function (error) {
        //操作失败的处理程序
   });
之所以能够使用链式调用,是因为then方法和catch方法调用后,都会返回promise对象。
        讲了那么多,如果你之前一点都没接触过Promise的话,现在一定很懵逼,没关系,下面我们用一个案例来串联前面的知识点,演示一下,认真阅读注释:
 //用new关键字创建一个Promise实例
   let pro = new Promise(function(resolve,reject){
        //假设condition的值为true
        let condition = true;

        if(condition){
            //调用操作成功方法
           resolve('操作成功');
            //状态:pending->fulfilled
        }else{
            //调用操作异常方法
           reject('操作异常');
            //状态:pending->rejected
        }
   });

   //用then处理操作成功,catch处理操作异常
   pro.then(function (res) {

        //操作成功的处理程序
       console.log(res)

   }).catch(function (error) {

        //操作失败的处理程序
       console.log(error)

   });
   //控制台输出:操作成功

Promise.all方法
Promise.all( )方法:接受一个数组作为参数,数组的元素是Promise实例对象,当参数中的实例对象的状态都为fulfilled时,Promise.all( )才会有返回。
//创建实例pro1
   let pro1 = new Promise(function(resolve){
        setTimeout(function () {
            resolve('实例1操作成功');
        },5000);
   });
   
   //创建实例pro2
   let pro2 = new Promise(function(resolve){
        setTimeout(function () {
            resolve('实例2操作成功');
        },1000);
   });

   
   Promise.all([pro1,pro2]).then(function(result){
        console.log(result);
   });
   //打印结果:["实例1操作成功", "实例2操作成功"]

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

Promise.race方法
Promise.race()方法:它的参数要求跟Promise.all( )方法一样,不同的是,它参数中的promise实例,只要有一个状态发生变化(不管是成功fulfilled还是异常rejected),它就会有返回,其他实例中再发生变化,它也不管了。
 //初始化实例pro1
   let pro1 = new Promise(function(resolve){
        setTimeout(function () {
            resolve('实例1操作成功');
        },4000);
   });

   //初始化实例pro2
   let pro2 = new Promise(function(resolve,reject){
        setTimeout(function () {
            reject('实例2操作失败');
        },2000);
   });

   Promise.race([pro2,pro1]).then(function(result){
        console.log(result);
   }).catch(function(error){
        console.log(error);
   });
   //打印结果:实例2操作失败

4、类基本用法
4.1类的属性和方法
声明一个类的写法:

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

给类添加属性和方法。

 

 

   上面的案例中,类体内有2个方法:constructor( )、getName()。

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

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

4.3类的静态方法

如何创建对象和使用对象的实例方法:

 

 

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

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

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

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

 4.4类的继承

ES6使用extends关键字来实现子类继承父类

 

 

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

 可以用super来引用父类

 

 

 

 

 

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

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

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

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

5、Module模块

5.1模块化的初衷

目前还没有浏览器支持ES6的module模块。

 

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

5.2模块Module

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

 

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

5.3导出Export

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

5.4导入Import

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

5.5模块化的实现

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

moduleB模块代码:

 

 

 moduleA模块代码:

 

 

 5.6批量导出

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

 

 

 

 

 

 5.7重命名导出的变量

 

 

 5.8整体导入

 

 

 5.9默认导出

 

 

 

 

 

 5.10注意事项

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

 

 

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

 

 

 

 

 

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

 

posted on 2020-08-06 20:41  _Luminary  阅读(30)  评论(0)    收藏  举报

导航