ES6精讲

ES6精讲

ES5语言的先天不足。比如变量提升,内置对象的方法不灵活、模块化实现不完善等等 为了后面vue、尤其是react框架做好准备,目前大部分公司的项目都是使用ES6。

ES6新特性:

1.let和const命令

2.es6的模板字符串

3.增强的函数

4.扩展的字符串、对象、数组功能

5.解构赋值

6.Symbol

7.Map和Set

8.迭代器和生成器

9.Promise对象

10.Proxy对象

11.async的用法

12.类class

13.模块化实现
各大浏览器最新版本ES6支持可以查看网址

强大的babel

1.被称为下一代的JavaScript编译器。可以将es6的代码转换成es5的代码,从而让浏览器获得支持。

2.这个课程我们只需要知道前端工具babel这个工具的作用,在这里不做过多赘述。
ES6阮一峰教程
MDN教程

let和const命令

var没有变量提升

 var a;
 // var
 console.log(a);//undefined
 a = 2;

1.let声明变量,没有变量提升

console.log(a);//Uncaught ReferenceError:Cannot access 'a' before initialization
let a = 10;
console.log(b);

2.是一个块作用域

if(1===1){
    let b = 10;
}
console.log(b);//b is not defined
let变量在函数内部定义(局部变量),函数外部,变量无法识别

3.不能重复声明

var a = 2;
var a = 4;
let a = 1;
let a = 3;
console.log(a);
var可以重复定义变量,let不能重复定义变量

var a = 2;
var a = 4;
let a = 1;
let a = 3;
console.log(a);
var可以重复定义变量,let不能重复定义变量

const 声明常量 一旦被声明 无法修改

console.log(max);
if(1===1){
    const max = 30;
}
const max = 30;
const max = 40;

max = 40;
console.log(max);

不能直接赋值对象内部变量的值,可用通过对象的属性对其进行赋值

const person = {
    name:'小马哥'
}
// person.name = 'alex';//可以常量对象内部的属性
person = {//html:50
    age:20
}
console.log(person);
es_01.png

作用1:for循环是个经典例子

···
var arr = [];
for (var i = 0; i < 10; i++) {
arr[i] = function() {
return i;
}
}
console.log(arr5);
···

var 具有变量提升,var i就瞬间执行完for(var i = 0; i < 10; i++)

es_02.png

···
const arr = [];
for (let i = 0; i < 10; i++) {
arr[i] = function() {
return i;
}
}
console.log(arr5);
···
es_03.png

作用2:不会污染全局变量

···
let RegExp = 10;
console.log(RegExp);//10
console.log(window.RegExp);//f RegExp(){native code}
···
建议:在默认情况下用const,而只有在你知道变量值需要被修改的情况使用let

模板字符串

使用tab键上面的反引号``,插入变量时使用${变量名}

···
const oBox = document.querySelector('.box');
let id = 1,
name = '小马哥';
let htmlStr = <ul> <li> <p id=${id}>${name}</p> </li> </ul>;
// oBox.innerHTML = "<ul><li><p id=" + id + ">" + name + "</p></li></ul>";
oBox.innerHTML = htmlStr;
···

函数之默认值_剩余参数

1.带参数默认值的函数

es5的写法

function add(a, b) {
    a = a || 10;
    b = b || 20;
    return a + b;
}
console.log(add());

es6写法

function add(a, b = 20) {
    return a + b;//50
}
console.log(add(30));

2.默认的表达式也可以是一个函数

function add(a, b = getVal(5)) {
    return a + b;
}

function getVal(val) {
    return val + 5;
}
console.log(add(10));//20

3.剩余参数:由三个点...和一个紧跟着的具名参数指定 ...keys

es5写法

function pick(obj) {
    let result = Object.create(null);//创建空的对象
    for(let i = 1;i < arguments.length;i++){
        console.log(arguments);//html:41
        result[arguments[i]] = obj[arguments[i]]
        console.log(arguments[i]);//html:43 author year 
    }
    return result;
}
let book = {
    title:'es6的教程',
    author:'小马哥',
    year:2019
}
let bookData = pick(book,'title','year','author');
console.log(bookData);//html:53
es_04.png

es6写法

function pick(obj, ...keys) {
    // ...keys 解决了arguments 的问题
    console.log(keys);//html:59 对应的参数保存到一个数组
    let result = Object.create(null);
    for (let i = 0; i < keys.length; i++) {
        result[keys[i]] = obj[keys[i]];
    }
    return result;
}

let book = {
    title: 'es6的教程',
    author: '小马哥',
    year: 2019
}
let bookData = pick(book, 'year', 'author');
console.log(bookData);//html:73
es_05.png
function checkArgs(...args) {
    console.log(args);//真数组
    console.log(arguments);//伪数组
}
checkArgs('a', 'b', 'c');
es_06.png

4.扩展运算符...

剩余运算符:把多个独立的参数合并到一个数组中(通常函数中使用),通常放在函数的形参上

扩展运算符:将一个数组分割,并将各个项作为分离的参数传给函数,通常将数组进行分割
es5写法

const maxNum = Math.max(20,30);
console.log(maxNum);
// 处理数组中的最大值,使用apply
const arr = [10, 20, 50, 30, 90, 100, 40];
console.log(Math.max.apply(null,arr));//es5写法  null是对象 arr是传入参数

es6 扩展运算法更方便

console.log(Math.max(...arr));//100
针对数组进行操作

es6的箭头函数

使用=>来定义 function(){}等于与 ()=>{}
es5写法

let add = function(a,b){
    return a + b;
}
console.log(add(10,20));

es6写法

let add = (a,b)=>{
    return a + b;
}
console.log(add(10,20));
//只有一个参数时候
let add = val => {
    return val + 5;
}
或者
let add = val => (val+5);
console.log(add(10));//15
或者
let add = (val1,val2) => val1+val2;//NaN   可以不加括号
let add = (val1,val2) => (val1+val2);//return中的表达式必须添加括号
或者
let fn = () => 'hello world' + 123;
console.log(fn());
或者
let getObj = id => {
    return {
        id: id,
        name:'小马哥'
    }
}
let obj = getObj(1);
console.log(obj);//输出对象 {id:1,name:'小马哥'}
或者
let getObj = id =>({
    id:id,
    name:'小马哥'
})
//let getObj = id =>({id:id,name:'小马哥'})
let obj = getObj(1);
console.log(obj);//输出对象 {id:1,name:'小马哥'}

闭包函数

let fn = (function(){
    return function(){
        console.log('hello world');
    }
})();
fn();
//fn得到的是整个return funcion函数,fn()执行return funcion函数
或者
let fn = (() => {
    return ()=>{
        console.log(hello world2);
    }
})();
fn();

箭头函数this指向和注意事项

es6没有this绑定
es5中this指向:取决于调用该函数的上下文对象

let PageHandle = {
    id: 123,
    init: function () {
        document.addEventListener('click',function(event) {
            // this.doSomeThings is not a function
            // console.log(this);  this指向document
            this.doSomeThings(event.type);//事件类型是click
        }.bind(this),false)//this指向PageHandle   false代表冒泡不冒泡
    },
    doSomeThings:function(type){
        console.log(`事件类型:${type},当前id:${this.id}`);
    }
}
PageHandle.init();
let PageHandle = {
    id: 123,
    init: function () {//定义方法的时候一定不要使用箭头函数
        //init:()=>{},整个的init的作用域链就不存在,智能往上寻找PageHandle的作用域链,是指向整个window
        // 箭头函数没有this指向,箭头函数内部this值只能通过查找作用域链来确定,一旦使用箭头函数,当前就不存在funcion函数的作用域链,在整个的init的作用域链上面
        document.addEventListener('click',(event)=>{
            this.doSomeThings(event.type);
        },false)
    },
    doSomeThings:function(type){
        console.log(`事件类型:${type},当前id:${this.id}`);
    }
}
PageHandle.init();

使用箭头函数的注意事项

1:使用箭头函数 函数内部没有arguments

let getVal = (a, b) => {//this指向window 使用箭头函数没有作用域链
    console.log(arguments);//arguments is not defined
    return a + b;
}
console.log(getVal(1, 3));

2.箭头函数不能使用new关键字来实例化对象

let Person = ()=>{
            
};
//function函数 也是一个对象,但是箭头函数不是一个对象
console.log(person);//没有constructor函数
let p = new person();

function函数 也是一个对象,但是箭头函数不是一个对象,它其实就是一个语法糖(表达式)

解构赋值是对赋值运算符的一种扩展

它针对数组和对象来进行操作

优点:代码书写上简洁易读
es5写法:

let node = {
    type:'iden',
    name:'foo'
}
let type = node.type;
let name = node.name;

es6写法:

完全解构

let {type,name} = node;
console.log(type,name);

复杂一点的对象:

不完全解构 可忽略

let obj = {
    a:{
        name:"张三"
    },
    b:[],
    c:'hello,world'
}
let {a} = obj;//a一定是当前对象的属性名
console.log(a);

剩余运算符:

let {a,...res} = obj;
console.log(res);//剩余的参数都放在一个对象中
es_07.png

默认值

let {a,b = 30} = {a:20};

对数组解构

//数组不完全解构
let arr = [1,2,3];
let [a,b] = arr;
console.log(a,b);

可嵌套

let [a,[b],c] = [1,[2],3];

扩展的对象的功能

es6直接写入变量和函数,作为对象的属性和方法
解决属性名和属性值重复的问题

const name = '小马哥',age = 20;
//es5的写法
const person = {
    name:name,
    age:age,
    sayName:function(){
        
    }
}
//es6的写法
const person = {
    name,//等价于name:name
    age,
    sayName(){
        console.log(this.name);
    }
}
person.sayName();

function fn(x,y) {
    return {x,y};
}
console.log(fn(10,20));

let cart = {
    wheel:4,
    set(newVal){
        if(newVal < this.wheel){
            throw new Error('轮子数太少了')
        }
        this.wheel = newVal;
    },
    get(){
        return this.wheel;
    }
}
// console.log(cart.get());
//设置器
cart.set(6);
//取值器
console.log(cart.get())

es5写法

属性表达式组合

const obj = {};
obj.isShow = true;

const name = 'a';
obj[name+'bc'] = 123;
console.log(obj);
es_08.png

函数组合

obj['f'+'bc'] = function(){
    console.log(this);
}
console.log(obj);
es_09.png
const name = 'a';
const obj = {
    isShow:true,
    [name+'bc']:123,
    ['f'+name](){
        console.log(this);
    }
}
console.log(obj);
es_10.png

es_12.png

对象的方法

is() 方法 ===

//比较两个值是否严格相等  即比较数值又比较类型
console.log(NaN === NaN);//false
console.log(Object.is(NaN,NaN));//true  +0 === -0

对象的合并

assign()方法 浅拷贝

Object.assign(target,obj1,obj2....)

返回合并之后的新对象

let newObj = Object.assign({},{a:1},{b:2});
console.log(newObj);
es_13.png

Symbol类型(新的数据类型)

原始数据类型Symbol ,它表示是独一无二的值

最大的用途:用来定义对象的私有变量

只是用Symbol声明

const name = Symbol('name');
const name2 = Symbol('name');//内存地址不一样
console.log(name === name2);//false
let s1 = Symbol('s1');
console.log(s1);
es_14.png
let s1 = Symbol('s1');
// console.log(s1);
let obj = {};
obj[s1] = '小马哥';
//简写
let obj = {
    [s1]:'小马哥'
};
es_15.png

如果用Symbol定义的对象中的变量,取值时一定要用[变量名]

console.log(obj[s1]);//html:28 小马哥
console.log(obj.s1);//html:29 undefined
//Symbol无法遍历
for(let key in obj){
    console.log(key); //没有输出,
} 
//对象中的变量不易操作
console.log(Object.keys(obj));//html:34 []

获取Symbol声明的属性名(作为对象的key)

let s = Object.getOwnPropertySymbols(obj);//[Symbol(s1)]
console.log(s[0]);//html:38 Symbol(s1)

反射对象

let m = Reflect.ownKeys(obj);//反射对象
console.log(m);//html:41 [Symbol(s1)]
es_16.png

Set集合数据类型(新的数据类型)

集合:表示无重复值的有序列表

let set = new Set();
console.log(set);//Set(0){}
es_17.png

添加元素

set.add(2);
set.add('4');
set.add('4');
set.add([1,2,3])
set.add(['hello','world',3]);

删除元素

set.delete(2);

校验某个值是否在set中

console.log(set.has('4'));//true

查看set集合的长度

console.log(set.size);
set.forEach((val,key)=>{
    console.log(val);
    console.log(key);//val = key
})
//set集合中值就是键,键就是值
//毫无意义

将set转换成数组

let set2 = new Set([1, 2, 3, 3, 3, 4]);
// 扩展运算符
let arr = [...set2];
console.log(arr);
es_18.png

1.set中对象的引用无法被释放

let set3 = new Set(),obj = {};
set3.add(obj);
// 释放当前的资源
obj = null;
console.log(set3);
es_19.png

解决方法:弱引用

let set4 = new WeakSet(),//弱引用
obj = {};
set4.add(obj);
// 释放当前的资源
obj = null;
console.log(set4);

WeakSet注意事项:

1.不能传入非对象类型的参数

2.不可迭代 不能遍历出来

3.没有forEach()

4.没有size属性


es_20.png

es_21.png

Map类型是键值对的有序列表,键和值是任意类型

let map = new Map();
consolo.log(map);
es_22.png

es_23.png
let map = new Map();
map.set('name','张三');
map.set('age',20);
console.log(map); 
console.log(map.get('name'));//张三   获取器
es_24.png
map.has('name');//true
map.delete('name');
map.clear();//全部清除
//键可以是任意值
map.set(['a',[1,2,3]],'hello');//键是['a',[1,2,3]]

可以直接new map的时候直接初始化

let m = new Map([
    ['a', 1],
    ['c', 2]
]);
console.log(m);

WeakMap弱map

数组的扩展方式

数组的方法 from() of()

1.from() 将伪数组转换成真正的数组

 function add() {
     // console.log(arguments);
     // es5转换
     let arr = [].slice.call(arguments);
     console.log(arr);
     // es6写法
     let arr = Array.from(arguments);
     console.log(arr);
 }
 add(1, 2, 3);

from()应用
html代码:

<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
</ul>

js代码:

let lis = document.querySelectorAll('li');
console.log(lis);//NodeList是集合
console.log(Array.from(lis));
es_25.png

扩展运算符 将伪数组转换成真正的数组

console.log([...lis]);

from() 还可以接受第二个参数,用来对每个元素进行处理

Array.from(lis,()=>{});
let liContents = Array.from(lis,ele => ele.textContent);
console.log(liContents);
es_26.png

2.of() 将任意的数据类型,转换成数组

console.log(Array.of(3, 11, 20, [1, 2, 3], {
    id: 1
}));

3.copywithin() 数组内部将指定位置的元素复制到其它的位置,返回当前数组

// 从3位置往后的所有数值,替换从0位置往后的三个数值
console.log([1, 2, 3, 8, 9, 10].copyWithin(0, 3));
//[8,9,10,8,9,10]

4.find() findIndex()

find()找出第一个符合条件的数组成员

findIndex()找出第一个符合条件的数组成员索引

// find()找出第一个符合条件的数组成员
let num = [1, 2, -10, -20, 9, 2].find((n)=>{
    return n<0;
})
//简写
let num = [1, 2, -10, -20, 9, 2].find(n => n < 0)
console.log(num);
//findIndex()找出第一个符合条件的数组成员的索引
let numIndex = [1, 2, -10, -20, 9, 2].findIndex(n => n < 0)
console.log(numIndex);

5.entries() keys() values() 返回一个遍历器 (可以使用for...of循环进行遍历)

keys() 对键名遍历

values() 对值遍历

entries() 对键值对遍历

console.log(['a','b'].keys());
es_27.png

遍历键

for (let index of ['a', 'b'].keys()) {
    console.log(index);
}

遍历值

for (let ele of ['a', 'b'].values()) {
    console.log(ele);
}
console.log(['a','b'].entries());//可以取到遍历器
es_28.png
for(let [index,ele] of ['a','b'].entries()){
    console.log(index,ele); 
}
es_29.png
let letter = ['a','b','c'];
let it = letter.entries();
console.log(it.next().value);
console.log(it.next().value);
console.log(it.next().value);
console.log(it.next().value);
es_30.png

6.includes() 返回一个布尔值,表示某个数组是否包含给定的值

console.log([1,2,3].includes(2));//true
console.log([1,2,3].includes('4'));//false  不用判断是否恒等于-1
// 之前 indexof()
console.log([1,2,3].indexOf('2') === -1);

迭代器Interator的用法

Iterator是一种新的遍历机制,两个核心

1.迭代器是一个接口,能快捷的访问数据,通过Symbol.iterator来创建迭代器 通过迭代器的next()获取迭代之后的结果

2.迭代器是用于遍历数据结构的指针(数据库的游标)

// 使用迭代  遍历器就是迭代器,迭代器就是遍历器
const items = ['one', 'two', 'three'];
console.log(items);//html:21
// 1.创建新的迭代器
const ite = items[Symbol.iterator]();
console.log(ite.next()); //{value: "one", done: false} done如果为false表示遍历继续 如果为true表示遍历完成
console.log(ite.next());
console.log(ite.next());
console.log(ite.next());//{value:undefined,done:true}
es_31.png

生成器Generator的用法

generator函数 可以通过yield关键字,将函数挂起(停留在当前位置),为了改变执行流提供了可能,同时为了做异步编程提供了方案

它普通函数的区别

1.function后面 函数名之前有个*

2.只能在函数内部使用yield表达式,让函数挂起(停留在当前位置)

function* func(){
    yield 2;
}
console.log(func());
es_32.png
function* func(){
    yield 2;
}
//返回一个遍历器对象 可以调用next()
let fn = func();
console.log(fn.next());//{value: 2, done: false}
console.log(fn.next());//undefined
function* func(){
    console.log('start');
    yield 2;
}
//第一次调用函数,只会调用生成器,没有返回值
let fn = func();
fn.next();//会打印 start 并且生成 {value: 2, done: false}
function* func() {
    console.log('one');
    yield 2;
    console.log('two');
    yield 3;
    console.log('end');   
}
// 返回一个遍历器对象 可以调用next()
let fn = func();
// console.log(o)
console.log(fn.next());
console.log(fn.next());
console.log(fn.next()); 

总结:generator函数是分段执行的,yield语句是暂停执行 而next()恢复执行

function* add() {
    console.log('start');//html:37
    // x 可真的不是yield '2'的返回值,它是next()调用 恢复当前yield()执行传入的实参
    let x = yield '2';
    console.log('one:'+x);//html:40
    let y = yield '3';
    console.log('two:'+y);//html:42
    return x+y;  //html:43
}
const fn = add();
console.log(fn.next()); ////html:46 {value:'2',done:false}
console.log(fn.next(20)); //html:47 {value:'3',done:false}
console.log(fn.next(30)); //html:48 {value:50,done:true}
es_33.png

使用场景1:为不具备Interator接口的对象提供了遍历操作

function* objectEntries(obj) {
    // 获取对象的所有的key保存到数组 [name,age]
    const propKeys = Object.keys(obj);
    for(const propkey of propKeys){
        yield [propkey,obj[propkey]]
    }
}


const obj = {
    name:'小马哥',
    age:18
}
obj[Symbol.iterator] = objectEntries;
console.log(obj);//html:65

for(let [key,value] of objectEntries(obj)){
    console.log(`${key}:${value}`);  
}
es_34.png

Generator的应用

bootCDN

Generator 部署ajax操作,让异步代码同步化

<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
//src通过bootCSDN查询
$.ajax({
    url: 'https://free-api.heweather.net/s6/weather/now?location=beijing&key=4693ff5ea653469f8bb0c29638035976',//和风天气接口
    method: 'get',
    success(res) {
        console.log(res);
    }
})
es_35.png

es_36.png

回调地狱

// 回调地狱
$.ajax({
    url: 'https://free-api.heweather.net/s6/weather/now?location=beijing&key=4693ff5ea653469f8bb0c29638035976',
    method: 'get',
    success(res) {
        // console.log(res);

        // 继续发送请求
        $.ajax({
            url: '',
            method: 'get',
            success(res1) {
            // 发送ajax
                $.ajax({
                    url: '',
                    method: 'get',
                    success(res2) {

                    // 发送ajax
                        $
                    }
                })
            }
        })
    }
})

用Generator生成器进行改写

function* main() {
    console.log('main');//html:45

    let res = yield request(
        'https://free-api.heweather.net/s6/weather/nowlocation=beijing&key=4693ff5ea653469f8bb0c29638035976'
    )
    console.log(res);//html:50

    // 执行后面的操作
    console.log('数据请求完成,可以继续操作');//html:53

}
const ite = main();
ite.next();

function request(url) {
    $.ajax({
        url,
        method: 'get',
        success(res) {
            ite.next(res);//第二次的调用
        }
    })
} 
es_37.png

加载loading...页面

数据加载完成...(异步操作)

loading关闭掉

function* load() {
    loadUI();
    yield showData();
    hideUI();
}

let itLoad = load();
    itLoad.next();//'加载loading...页面'和'数据加载完成'
function loadUI() {
    console.log('加载loading...页面');
}
function showData() {
    // 模拟异步操作
    setTimeout(() => {
        console.log('数据加载完成');
        itLoad.next();//'隐藏loading...页面'
    }, 1000);
}
function hideUI() {
    console.log('隐藏loading...页面');

}

Promise基本使用

Promise 承诺

相当于一个容器,保存着未来才会结束的事件(异步操作)的一个结果

各种异步操作都可以用同样的方法进行处理 axios(ajax库)

特点:

1.对象的状态不受外界影响 处理异步操作 三个状态 Pending(进行) Resolved(成功) Rejected(失败)

2.一旦状态改变,就不会再变,任何时候都可以得到这个结果针对:Resolved(成功) Rejected(失败

let pro = new Promise(function(resolved,rejected) {
    //执行异步操作
    
})
console.log(pro);
es_38.png
let pro = new Promise(function(resolved,rejected) {
    //执行异步操作
    let res = {
        code: 201,
        data:{
            name:'小马哥'
        },
        error:'失败了'
    }
    setTimeout(() => {
        if(res.code === 200){
            resolved(res.data);
        }else{
            rejected(res.error);
        }
    }, 1000);
})

console.log(pro);
pro.then((val)=>{
    console.log(val);

},(err)=>{
    console.log(err);

});

封装函数

 //有点像闭包函数 
function timeOut(ms) {
    return new Promise((resolved,rejected)=>{
         setTimeout(() => {
            resolved('hello promise success!!')
         }, ms);
     })
 }
 timeOut(2000).then((val)=>{
    console.log(val);

 })

Promise应用

promise封装的相当于就是axios

const getJSON = function(url){
    return new Promise((resolve,reject)=>{
        const xhr = new XMLHttpRequest();
        xhr.open('GET',url);
        xhr.onreadystatechange = handler;
        xhr.responseType = 'json';
        xhr.setRequestHeader('Accept','application/json');
        //发送
        xhr.send();
        function handler(){
            console.log(this);//html:107 this指向xhr对象
            if(this.readyState === 4){
                if(this.status == 200){
                    resolve(this.response.HeWeather6);
                }else{
                    reject(new Error);
                }
            }
        }
    })
}

let a = getJSON('https://free-api.heweather.net/s6/weather/now?location=beijing&key=4693ff5ea653469f8bb0c29638035976').then((data)=>{
   // console.log(data);//是一个对象
    return data[0];//返回
},(error)=>{
    console.log(error(this.statusText));
}).then((obj)=>{
    console.log(obj);
})
console.log(a);//a是一个promise对象
es_39.png

es_40.png

then()方法

then() 第一个参数是relove回调函数,第二个参数是可选的 是reject状态回调的函数

then()返回一个新的promise实例,可以采用链式编程


es_41.png
getJSON('https://free-api.heweather.net/s6/weather/now?location=beijing&key=4693ff5ea653469f8bb0c29638035976').then((data)=>{
    console.log(data);
 }).then(null,error => {})//不友好
或者
.catch(error=>{});

promise的其他方法

resolve() reject() all() race() done() finally()

resolve()能将现有的任何对象转换成promise对象

let p = new Promise(resolve=>resolve('foo'));//直接return resolve
let p = new Promise(resolve=>{
    return resolve('foo');
})
//和下面代码等价
let p = Promise.resolve('foo');
console.log(p);//html:131
p.then((data)=>{
    console.log(data);//html:133
}) 
es_42.png

all()方法:提供执行并行的异步操作行为

// 应用:一些游戏类的素材比较多,等待图片、flash、静态资源文件 都加载完成 才进行页面的初始化
let promise1 = new Promise((resolve, reject) => {});
let promise2 = new Promise((resolve, reject) => {});
let promise3 = new Promise((resolve, reject) => {});

let p4 = Promise.all([promise1, promise2, promise3]);

p4.then(()=>{
// 三个都成功  才成功
}).catch(err=>{
// 如果有一个失败 则失败
}) 

race() 某个异步请求设置超时时间,并且在超时后执行相应的操作

// 1 请求图片资源
function requestImg(imgSrc) {
    return new Promise((resolve, reject) => {
        const img = new Image();
        img.onload = function () {
            resolve(img);
        }
        img.src = imgSrc;
    });
}

function timeout() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject(new Error('图片请求超时'));
        }, 1000);
    })
}
Promise.race([requestImg('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1566364222518&di=b3c6d411bb23f17d1798fc6be3325ad5&imgtype=0&src=http%3A%2F%2Fpic.k73.com%2Fup%2Fsoft%2F2016%2F0102%2F092635_44907394.jpg'),timeout()]).then(data=>{
    console.log(data);
    document.body.appendChild(data);

}).catch(err=>{
    console.log(err);

});
es_43.png

done()和finally()方法

//不管成功没有都会走done()和finally()方法
server.listen(3000).then(()=>{

}).finally(server.stop());

async的用法

Generator Promise async 1.解决回调地域(函数嵌套的调用) 2.使得异步操作显得更加方便

作用:使得异步操作更加方便

基本操作 async它会返回一个Promise对象 then catch

async是Generator的一个语法糖

async function f() {
    // return await 'hello async';
    let s = await 'hello world';
    let data = await s.split('');
    return data;
}
console.log(f());
es_44.png
async function f() {
    // return await 'hello async';
    let s = await 'hello world';
    let data = await s.split('');
    return data;
}
// console.log(f());
// 如果async函数中有多个await 那么then函数会等待所有的await指令 运行完的结果 才去执行
f().then(v => {
    console.log(v)
}).catch(e => console.log(e));
async function f2() {
// throw new Error('出错了');
    try {
        await Promise.reject('出错了');
    } catch (error) {

    }
    return await Promise.resolve('hello');
}
f2().then(v => console.log(v)).catch(e => console.log(e));

async应用

需求: 想获取和风天气 现在now的数据

const getJSON = function (url) {
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open('GET', url);
        xhr.onreadystatechange = handler;
        xhr.responseType = 'json';
        xhr.setRequestHeader('Accept', 'application/json');
        // 发送
        xhr.send();

        function handler() {

            if (this.readyState === 4) {
                if (this.status === 200) {
                    resolve(this.response);
                } else {
                    reject(new Error(this.statusText));
                }
            }       

        }
    })
}

async function getNowWeather(url) {
    // 发送ajax 获取实况天气
    let res = await getJSON(url);
    console.log(res);
    // 获取HeWeather6的数据   获取未来3~7天的天气状况
    let arr = await res.HeWeather6;
    return arr[0].now;
}
getNowWeather(
    'https://free-api.heweather.net/s6/weather/now?location=beijing&key=4693ff5ea653469f8bb0c29638035976')
    .then(now => {
        console.log(now);
    })
es_45.png

class类的用法

// es5造类
function Person(name,age) {
    this.name = name;
    this.age = age;
}
Person.prototype.sayName = function() {
    return this.name;
}
let p1 = new Person('小马哥',28);
console.log(p1);

es6写法

class Person {
    // 实例化的时候会立即被调用
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    //sayName() {
    //  return this.name
    //},
    //sayAge() {
    //  return this.age
    //}

}
// 通过Object.assign()方法一次性向类中添加多个方法
Object.assign(Person.prototype, {
    sayName() {
        return this.name
    },
    sayAge() {
        return this.age
    }
})
let p1 = new Person('小马哥', 28);
console.log(p1);

类的继承

// 使用关键字 extends
class Animal{
    constructor(name,age) {
        this.name = name;
        this.age = age;
    }
    sayName(){
        return this.name;
    }
    sayAge(){
        return this.age;
    }
}

class Dog extends Animal{
    constructor(name,age,color) {
        super(name,age);//super超类
        // Animal.call(this,name,age);
        this.color = color;
    }
    // 子类自己的方法
    sayColor(){
        return `${this.name}是${this.age}岁了,它的颜色是${this.color}`
    }
    // 重写父类的方法   super等于Animal.prototype
    sayName(){
        return this.name + super.sayAge() + this.color;
    }

}
let d1 = new Dog('小黄',28,'red');
console.log(d1.sayColor());
console.log(d1.sayName());

// 思考:如何让多个类 混入到一个类中????

Mix-ins / 混入

JS 没有多继承。

确切的说,绝大部分 OOP 语言都不支持多继承,因为没有什么理论可以完美的解决继承冲突问题,所以干脆就不去碰。

不过 JS 里可以通过 mixin 的方式将两个类型的成员混合到一个成员上,实现伪多继承。

实现方式看 MDN 这章

抽象子类或者 mix-ins 是类的模板。 一个 ECMAScript 类只能有一个单超类,所以想要从工具类来多重继承的行为是不可能的。子类继承的只能是父类提供的功能性。因此,例如,从工具类的多重继承是不可能的。该功能必须由超类提供。

一个以超类作为输入的函数和一个继承该超类的子类作为输出可以用于在ECMAScript中实现混合:

var calculatorMixin = Base => class extends Base {
  calc() { }
};

var randomizerMixin = Base => class extends Base {
  randomize() { }
};

使用 mix-ins 的类可以像下面这样写:

class Foo { }
class Bar extends calculatorMixin(randomizerMixin(Foo)) { }

ES6的模块化实现

<script type='module'>
    // CommonJS(服务器,实际就是对象)和AMD(浏览器)
    // ES6 module 浏览器和服务器通用模块的方案
    import Person,{name,age,sayName} from './modules/index.js'
    // import * as f from './modules/index.js'
    // console.log(Person);
    const p = new Person();
    p.sayAge();
    // console.log(f.default);
    // console.log(name,age,sayName());
</script>
es_47.png

es6模块功能主要有两个命令构成:export和import

export用于规定模块的对外接口 import用于输入其它模块提供的功能

一个模块就是独立的文件

/* export const name = '张三';
export const age = 18;
export function sayName(){
    return 'my name is 小马哥';
} */
// export {sayName}

const name = '张三';
const age = 18;
function sayName() {
    return 'my name is 小马哥';
}
export {
    name,age,sayName
}
/* const obj = {
    foo:'foo'
} */
class Person{
    constructor(){

    }
    sayAge(){
        console.log('16');
        
    }
}

export default Person;
es_46.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,825评论 4 377
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,887评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,425评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,801评论 0 224
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,252评论 3 299
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,089评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,216评论 2 322
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 31,005评论 0 215
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,747评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,883评论 2 255
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,354评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,694评论 3 265
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,406评论 3 246
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,222评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,996评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,242评论 2 287
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 36,017评论 2 281

推荐阅读更多精彩内容