【ES6】学Vue前必须掌握的内容(下)

目录

Symbol 数据类型

Set 数据结构

Map 数据结构

promise ⭐

① 同步、异步

② 含义

③ 基本使用

④ 综合案例

for...of

Generator函数

async函数⭐

类class ⭐

模块⭐

① 概念

② 基本使用

③ 应用


Symbol 数据类型

ES6引入了一种新的数据类型Symbol,表示独一无二的值。它是JS的第七种数据类型,前六种分别是number、string、undefined、null、boolean、object。

特点:

  • Symbol值是唯一的,解决命名冲突的问题;
  • Symbol值不能与其他数据进行计算,包括字符串的拼接;
  • for...in、for...of 不会遍历Symbol属性。

Symbol是函数,但并不是构造函数。创建一个Symbol数据类型:

const symbol=Symbol();
console.log(typeof(symbol));//symbol

Symbol的使用

1.作为对象的属性值
const sym=Symbol();
const obj={ name:'hua' };
obj[sym]='aaa';          //注意!只能通过属性选择器[]来添加和读取
console.log(obj, obj.sym, obj[sym]);  // {name:'hua',Symbol():'aaa'} undefined aaa
for(let k in obj){
    console.log(obj[k]); // hua
}

2.定义常量
const m=Symbol('my');

Set 数据结构

Set类似于数组,但值都是唯一不重复的。Set本身是一个构造函数,通过new Set()生成一个Set实例。

const set=new Set();

const set2=new Set([1,2,2,3,3,3]);
console.log(set2);//Set(3) {1,2,3} //不是数组,是Set数据结构
console.log([...set2]);//[1,2,3] //数组

Map 数据结构

Map类似于对象,也是键值对的集合,但它的键不限于字符串。也就是说Object结构提供了“字符串-值”的对应,Map结构提供了“值-值”的对应,是一种更为完善的Hash结构实现。

const map=new Map();
map.set(key,value);//添加
map.get(key);//通过键获取值
map.delete(key);//删除

Map的键实际上是和内存地址绑定的,只要内存地址不一样,就视为两个键。

const map=new Map();
map.set(['b'],1);
console.log(map.get(['b'])); //undefined
const a=['b'];
map.set(a,1);
console.log(map.get(a));     //1

promise ⭐

① 同步、异步

主线程执行同步任务完毕后,查询任务队列是否还有异步任务。

② 含义

Promise是ES6引入的异步编程的一种新解决方案。本身是一个构造函数。

简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

Promise 对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)、rejected(已失败)。

注意:

  • 一个 promise对象只能改变一次状态,成功或者失败后都会返回结果数据。
  • 状态变化只有两种可能:从 pending 变为 fulfilled 和 从 pending 变为 rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。
  • 后文中的 resolved 只指 fulfilled状态,不包括 rejected。

③ 基本使用

之前遇到的异步任务都是一次异步,如果需要多次调用异步函数,是通过“函数瀑布”来实现的,这种也称为“回调地狱”。

//1s后开始打印,共输出三次,每次间隔1s
setTimeout(() => {
    console.log('first');
    setTimeout(() => {
        console.log('second');
        setTimeout(() => {
            console.log('third');
        },1000)
    },1000)
},1000)

 在一个复杂的程序当中,用 "函数瀑布" 实现的程序无论是维护还是异常处理都是一件特别繁琐的事情,而且会让缩进格式变得非常冗赘。下面展示用Promise实现相同功能:

new Promise(function(resolve,reject){
    setTimeout(() => {
        console.log('first');
        resolve();
    },1000)
}).then(()=>
    new Promise(function(resolve,reject){
        setTimeout(() => {
            console.log('second');
            resolve(); 
        }, 1000);               
    })
).then(function(){
    setTimeout(() => {
        console.log('third');
    },1000)
})

 解释一下上面的代码:

Promise 构造函数只有一个参数,这个参数是一个函数,该函数在构造之后会直接被异步运行,所以也被称为起始函数起始函数有两个参数 resolve reject,它们都是函数,由 JavaScript 引擎提供,不用自己部署。

  • resolve函数的作用是,将Promise对象的状态从pending变为resolved(未完成->成功),在异步操作成功时调用,并将异步操作的结果作为参数传递出去;
  • reject函数的作用是,将Promise对象的状态从pending变为rejected(未完成->失败),在异步操作失败时调用,并将异步操作报出的错误作为参数传递出去。
  • resolve 和 reject 的作用域只有起始函数,不包括 then 以及其他序列。
  • then方法可以接受两个回调函数作为参数,第一个回调函数是Promise对象的状态改变为 resoved 时调用,第二个回调函数是 Promise 对象的状态变为 rejected 时调用。其中第二个参数可以省略。
new Promise(function(resolve,reject){
    let a=1;
    let b=2;
    if(b!=2){
        reject('error!');
    }
    else{
        resolve(a+b);
    }
}).then(function(value){console.log('a+b='+value);},function(err){console.log(err)})

 上面代码的then方法的第二个参数可以省略,然后使用catch方法,即:

new Promise(function(resolve,reject){
    let a=1;
    let b=2;
    if(b!=2){
        reject('error!');
    }
    else{
        resolve(a+b);
    }
}).then(function(value){
    console.log('a+b='+value);
}).catch(function(err){
    console.log(err);
})

Promise.prototype.catch()方法是.then(null / undefined, rejuctoin)的别名,用于指定发生错误时的回调函数。

  • 一般来说,不要在then()方法里定义reject状态的回调函数(即then的第二个参数),而是使用catch()方法。
  • Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一catch个语句捕获。
  • then块默认会向下顺序执行,return是不能中断的,可以通过throw来跳转至catch实现中断。

 finally() 方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。

const promise=new Promise((resolve,reject)=>{});
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
  • finally方法的回调函数不接受任何参数

④ 综合案例

let a=+prompt('请输入一个数字');
var promise =new Promise(function(resolve,reject){
    //To Do 要异步执行的事情,这个异步执行的事情有可能成功执行完毕,那么Promise将是fulfilled状态,如果执行失败则是rejected;
    //下面测试代码,人为设置为rejected状态;
    if(a!=0){resolve(a/2);}
    else{reject("不能为0"); }    
})
promise.then(//调用第一个then()
    success=>{
        console.log("异步执行成功,状态为fulfilled,成功后返回的结果是:"+success);
        return(" 当前 success ");
    },
    error=>{
        console.log("异步执行失败,状态为rejected,失败后返回的结果是:"+error);
        return(" 当前 error ");
    }
).then(
    //调用第二个then() 因为调用第一个then()方法返回的是一个新的promise对象,此对象的状态由上面的success或者error两个回调函数的执行情况决定的:
    //如果回调函数能正常执行完毕,则新的promise对象的状态为fulfilled,下面执行success2,如果回调函数无法正常执行,则promise状态为rejected;下面执行error2
    success2=>{
        console.log("第一个then的回调函数执行成功 成功返回结果:"+success2);
        throw(" 当前 success2 ");//自定义异常抛出
    },
    error2=>{
        console.log("第一个then的回调函数执行失败 失败返回结果:"+error2);
        return(" 当前 error2 ");
    }
).catch(err=>{
    //当success2或者error2执行报错时,catch会捕获异常;
    console.log("捕获异常:"+err);
}).finally(()=>{
    console.log('end');
});

 输出结果如下:

for...of

遍历器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。遍历器对象本质上,就是一个指针对象。

ES6引入了 for...of 循环,作为遍历所有数据结构的统一的方法。

一个数据结构只要部署了 Symbol.iterator 属性,就被视为具有 iterator 接口,就可以用 for...of 循环遍历它的成员。也就是说, for...of 循环内部调用的是数据结构的 Symbol.iterator 方法。

const arr=['a','b','c'];
for(let v of arr){
    console.log(v);      //'a' 'b' 'c'
    console.log(arr[v]); //undefined undefined undefined
}
for(let k in arr){
    console.log(k);      //'0' '1' '2'
    console.log(arr[k]); //'a' 'b' 'c'
}

数组的键名是数字,但是for...in中是以字符串的形式返回的。for...in主要为遍历对象而设计,不适用于遍历数组。对于普通的对象,for...of 结构不能直接使用,不然会报错,必须部署了 Iterator 接口后才能使用。

Generator函数

Generator 函数是一个普通函数,但是有两个特征。

  • function 关键字与函数名之间有一个星号;
  • 函数体内部使用 yield 表达式,定义不同的内部状态;
  • 调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,即上面提到的Iterator对象。
function* myGenerator(){
    yield 1;
    yield 'a';
    return 'end';
}
let mg=myGenerator();
console.log(mg.next()); //{value:1,done:false}
console.log(mg.next()); //{value:'a',done:false}
console.log(mg.next()); //{value:'end',done:true}

必须调用遍历器对象的 next 方法,使得指针移向下一个状态,即下一个yield表达式(或return语句)。换言之,Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。

 next方法:一般情况下,next方法不传入参数的时候,yield表达式的返回值是undefined,当next传入参数的时候,该参数会作为上一步yield的返回值。

function* myGenerator(){
    let x=yield 1;
    console.log(x);  //next无参时undefined,有参时输出参数first
    return ;         //无参时undefined
}
let mg=myGenerator();
//console.log(mg.next());
console.log(mg.next('first'));
console.log(mg.next());

async函数⭐

async函数就是 Generator 函数的语法糖

async function test1(){
    return 1;
}
console.log(test1());          //Promise对象

async function test2(){
    return Promise.resolve(2);
}
console.log(test2());          //Promise对象

async function test3(){
    const p=Promise.resolve(3);
//下面两部分等价
    p.then(data=>{
        console.log(data);
    })
//
    const data=await p;
    console.log(data);
}
console.log(test3());           //Promise对象
  • return返回的不是一个Promise类型的对象,返回的结果就是resolved(fulfilled)状态的Promise。
  • return返回的是一个Promise类型的对象,返回值成功就成功。
  • await表达式相当于Promise.then成功的情况。
async function test3(){
    //const data=await 3;
    const data=await Promise.resolve(3);
    console.log(data);
}
test3();

async function test4(){
    const p=Promise.reject(4);
    try{
        const data=await p;
        console.log('success '+data);
    }
    catch(err){
        console.log('failure '+err);
    }
}
test4();
  • await 3相当于await Promise.resolve(3);
  • Promise.catch异常的情况对应 try...catch。

类class ⭐

ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。

class lei{
    constructor(age){
        this.age=age;
    }
    fangfa(){
        console.log('方法不需要写function');
    }
}
let l=new lei(18);
console.log(l.age); //18
l.fangfa(); //方法不需要写function
  • 通过class关键字创建类,类名首字母大写;
  • 类里面有个constructor函数,可以接受传递过来的参数,同时返回实例对象;只要new生成实例化对象,就会自动调用该函数,即使不写也会自动生成;
  • 生成实例化对象new不能省略;
  • 方法不需要写function。
class Father {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    sum(){ console.log(this.x+this.y); }
    father(){ return ('我是父亲'); }
}
class Son extends Father {
    constructor(x,y){
        super(x,y);
        this.x=x;
        this.y=y;
    }
    son() {
        console.log(super.father()+'的儿子' );
    }
    sub(x,y){ console.log(this.y-this.x) }
}
let son = new Son(1, 2);
console.log(son); //Son {x: 1, y: 2}
son.sum();  // 3
son.son();  //我是父亲的儿子
son.sub();  //1
  • 继承extends,super()。
  • 必须先调用父类的构造函数才能写子类构造函数的this。
  • constructor的this指向实例对象,方法的this指向调用者。

模块⭐

① 概念

模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。

优点:

  • 防止命名冲突;
  • 代码复用;
  • 高维护性。

② 基本使用

ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。

一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。

//分别暴露
export let name='hua';       
export function fn(){
    console.log('module');
}
//统一暴露
let name='hua';
function fn(){
    console.log('module');
}
export{name,fn};            
<script type="module">
//通用方式
    import * as m from "../ES6/module初学";
    console.log(m.name); //hua
    m.fn();              //module
//解构方式
    import {name,fn} from "../ES6/module初学";
    console.log(name);   //hua
    fn();                //module
</script>

 // 默认暴露(常用) 

//默认暴露
export default{
    age:18,
    fun:function(){
        console.log('默认暴露')
    }
}

<script type="module">
//通用
    import * as m from "../ES6/module初学";
    console.log(m.default.age);   //18
    m.default.fun();              //默认暴露
//解构
    import {default as m} from "../ES6/module初学";
    console.log(m.age);
    m.fun();
//简便,仅限默认暴露使用
    import m from "../ES6/module初学";
    comsole.log(m.age);
    m.fun();
</script>
  • 重名时可用 as 取别名

③ 应用

1) 按需加载:import() 可以在需要的时候,再加载某个模块

button.addEventListener('click',event=>{
    import("../ES6/module初学")
     .then(load=>{
        load.open();
    })
     .catch(err=>{
        console.log(err);
    })
})

上面代码中,import() 方法放在 click 事件的监听函数之中,只有用户点击了按钮,才会加载这个模块。

 2) 条件加载:根据不同的情况,加载不同的模块

if(xxx){
    import('moduleA').then(...);
}else{
    import('moduleB').then(...);
}

上面代码中,如果满足条件,就加载模块 A,不满足则加载模块 B。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值