ECAMScript6基础知识

一、ES介绍

1.1 什么是ECAMScript

ES全称ECMAScript,是脚本语言的规范,而平时经常编写的JavaScript,是EcmaScript的一种实现,所以ES新特性其实指的就是JavaScript的新特性。

ECMAScript是由Ecma国际通过ECMA-262标准化的脚本程序设计语言。

1.2 什么是ECMA-262

Ecma国际制定了许多标准,而ECMA-262只是其中的一个,所有的标准列表查看

http://www.ecma-international.org/publications/standards/Standard.htm

1.3 ECMA-262历史

http://www.ecma-international.org/publications/standards/Ecma-262-arch.htm

注:从ES6开始,每年发布一个版本,版本号比年份最后一位大1

1.4 谁在维护ECMA-262

TC39(Technical Committee 39)是推进ECMAScript发展的委员会。其会员都是公司(其中主要是浏览器厂商,有苹果,谷歌,微软,因特尔等)。TC39定期召开会议,会议由会员公司的代表与特邀专家出席。

1.5 为什么要学习ES6

  • ES6的版本变动内容最多。具有里程碑意义
  • ES6加入许多新的语法特性,编程实现更简单、高效
  • ES6是前端发展趋势

1.6 ES6兼容性

http://kangax.github.io/compat-table/es6/ 可查看兼容性

二、ES6-let变量声明

1、let变量声明的格式

与 var 声明变量格式一样

2、let声明变量的特性

(1)变量不能重复声明

let star = '罗志祥';
let star = '小猪';

(2)块级作用域,代码只在代码块内有效

{
   let girl = '周扬青';
}
   console.log(girl);    //控制台显示  girl is not defined

(3)不存在变量提升(变量在声明之前,不能使用该变量)

console.log(song);
let song = '稻香';    //控制台显示 Cannot access 'song' before initialization

(4)不影响作用域链

        {
            let school = '清华大学';

            function fn() {
                console.log(school);
            }
            fn();
        }

3、let件经典案例

let item = document.querySelectorAll('.item');
//1、常规var用法
for (var i = 0; i < item.length; i++) {
            item[i].addEventListener('click', function() {
                this.style.background = 'pink';
            })
        }

//2、使用let变量声明用法
for (let i = 0; i < item.length; i++) {
            item[i].addEventListener('click', function() {
                item[i].style.background = 'pink';
            })
        }

三、ES6-conset声明常量

1、conset声明常量格式

常量:值不能修改的量

与var let 一样

2、注意事项

(1)一定要赋初始值

const A;   //报错

(2)一般常量使用大写(潜规则)

const a = 1000;

(3)常量的值不能修改

const SCHOOL = '清华大学';
SCHOOL = 'ATM';

(4)块级作用域

{
  const PLAYER = 'UZI';
}
  console.log(PLAYER);     //PLAYER is not defined

(5)对于数组和对象的元素修改,不算做对常量的修改,不会报错

const TEAM = ['UZI', 'MXLG', 'Ming', 'Letme'];
TEAM.push('Meiko');

四、ES6变量的解构赋值

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

1、数组的解构

const F4 = ['貂蝉', '蔡文姬', '虞姬', '甄姬'];
let [diao, cai, yu, zhen] = F4;
console.log(diao);    //貂蝉
console.log(cai);     //蔡文姬
console.log(yu);      //虞姬
console.log(zhen);    //甄姬

2、对象的解构

 const diao = {
            name: '貂蝉',
            age: '不详',
            zhandou: function() {
                console.log('我可以五连绝世');
            }
        };

let {zhandou} = diao;
zhandou();   //我可以五连绝世

五、ES6模板字符串

ES6引入新的声明字符串的方式 :[``] 、  ' ' 、 " "。

1、声明

let str = `我也是一个字符串哦`;
console.log(str, typeof str);

2、特性

① 内容中可以直接出现换行符

let str = `<ul>
               <li>王者荣耀</li>
               <li>金铲铲之站</li>
               <li>原神</li>
           </ul>`;

② 可以直接进行变量拼装

let lovest = '林宥嘉';
let out = `${lovest}是我心目中最棒的歌手`;
console.log(out);   //林宥嘉是我心目中最棒的歌手

六、对象的简化写法

ES6允许在大括号里面,直接写入变量和函数,作为对象的属性和方法

这样的书写更加简洁

let name = '甄姬';
        let change = function() {
            console.log('阿宓会带来不幸');
        }

const school = {
            name,
            change,
            improve() {
                console.log("我们可以提高你的技能");
            }
        }
        console.log(school);

七、箭头函数以及声明特点

ES6允许使用箭头(=>)定义函数

1、箭头函数语法结构

//1、常规写法
let fn = function() {
          }

//2、使用箭头函数
let fn = () => {
          }



//实例
let fn = (a, b) => {
        return a + b;
    }
let result = fn(1, 2);
console.log(result);         //3

2、特点

        2.1  this是静态的,this始终指向函数声明时所在的作用域下的this的值

function getName () {
     console.log(this.name);
                  }

let getName2 = () >= {
     console.log(this.name);
                  }

//设置window对象的name属性
window.name = '吃什么';
const food = {
        name: "西瓜",
    }

      2.2 箭头函数不能作为构造函数去实例化对象

let Person = (name, age) => {
        this.name = name;
        this, age = age;
    }
 let me = new Person('xiao', 30);
 console.log(me); //   Person is not a constructor

       2.3 箭头函数不能使用arguments变量

let fn = () => {
        console.log(arguments);
    }
fn(1, 2, 3); //arguments is not defined

3、箭头函数的简写

        3.1 当形参有且只有一个的时候,可省略小括号

//1、原始写法
let add = (n) => {
    return  n+n;
              }
console.log (add(9));

//2、简写
let add = n => {
    return  n+n;
              }
console.log (add(9));    //18

        3.2  当代码体只有一条语句的时候,此时return必须省略,语句的执行结果就是函数的返回值,此时省略花括号

//1、原始写法
let pow = (n) => {
    return n*n;
             }
console.log(pow(5));

//2、简写
let pow = n => n*n;
console.log(pow(5));   //25

4、实践与应用

        4.1  点击div 2s 后颜色变为天蓝色

<div class=“ad”></div>

//1、原始写法
let ad = document.querySelectior('.ad');
ad.addEventListener('click',function(){
       // 保存this的值   因为此时定时器的初始写法为window.setTimeout(),需要特殊声明
         let _this = this;
       //定时器
         setTimeout(function(){
           _this.style.background = 'skyblue';
         }.2000);
});

//2、简写
let ad = document.querySelectior('.ad');
ad.addEventListener('click',function(){
         setTimeout(() => {
          //此时的this指向的是声明函数下的this ad
         this.style.background = 'skyblue';
         }.2000);
});

       4.2  从数组中返回偶数元素

const arr = [1, 6, 9, 10, 100, 25];
//1、原始写法
const result = arr.filter(function(item) {
     if(item % 2 === 0 ) {
          return true;
      }else {
          return false;
      }
    })
console.log(result);

//2、简写
const result = arr.filter (item => item % 2 === 0);
console.log(result);    //Array(3)

5、总结

箭头函数适合于this无关的回调,如:定时器,数组的方法回调。

箭头函数不适合与this 有关的回调,如:dom事件回调,对象的方法。

八、函数参数默认值

ES6允许给函数参数(形参)赋值初始值

1、形参初始值,具有默认的参数,一般位置要靠后

function add(a, b, c = 10) {
            return a + b + c;
        }
let result = add(1, 2);
console.log(result);    //1+2+10=13

2、可与解构赋值相结合

function connect ({host,username,password,port}) {
       console.log(host);
       console.log(username);
       console.log(password);
       console.log(port);
      }
connect ({
    host: 'localhost';
    username;'root';
    password: 'root';
    port: 3306
   })

3、rest参数

ES6 引入rest参数,用于获取函数的实参,用来代替arguments。

rest参数必须要放到参数最后面

function date(...args) {
    console.log(args);
}
date('白芷', '陈皮', '决明子');   // ['白芷', '陈皮', '决明子']
function fn(a, b, ...args) {
    console.log(a);      //1
    console.log(b);      //2
    console.log(args);   //[3, 4, 5, 6]
}
 fn(1, 2, 3, 4, 5, 6); 

九、扩展运算符

1、语法结构

【...】 扩展运算符能够将数组转行为逗号分隔的参数序列

const tyboys = ['易烊千玺', '王源', '王俊凯']; // => '易烊千玺', '王源', '王俊凯'
function chunwan (){
     console.log(arguments);
}
chunwan(...tfboys);  //等同于 chunwan('易烊千玺', '王源', '王俊凯')

2、扩展运算符的运用

        2.1 数组的合并

const kuaizi = ['王太利', '肖央'];
const fenghuang = ['曾毅', '玲花'];
const zuixuanxiaopingguo = [...kuaizi,...fenghuang];
console.log(zuixuanxiaopingguo);

        2.2 数组的克隆(引用类型数据,浅拷贝)

const sanzhihua = ['E','G','M'];
const sanyecao = [...sanzhihua]; 
console.log(sanyecao);

        2.3 将伪数组转为真正的数组

const divs = document.querySelectorAll('div');
const divArr = [...divs];
 console.log(divArr);

十、Symbol

1、Symbol的基本使用

     ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,是一种类似于字符串的数据类型。

拓展:JavaScript语言的第七种数据类型     USONB

          U:  undefined

          S: string  symbol

          O:  object

          N:  null   number

          B: boolean

        1.1 Symbol的特点

(1)Symbol的值是唯一的,用来解决命名冲突的问题

let s = Symbol();
console.log(s, typeof s);
let s2 = Symbol('王者荣耀');
let s3 = Symbol('王者荣耀');
console.log(s2 === s3); /* false */

(2)Symbol值不能与其他数据进行运算

(3)Symbol定义的对象属性不能使用for...in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名。

let s4 = Symbol.for('王者荣耀');
let s5 = Symbol.for('王者荣耀');
console.log(s4 === s5); /* true */

       1.2  Symbol创建对象属性         

let game = {
            name: '俄罗斯方块',
            up: function() {},
            down: function() {}
        };
//声明一个对象
let methods = {
            up : Symbol(),
            down : Symbol()
          };
game[methods.up] = function(){
         console.log('我可以改变形状');
             }
game[methods.down] = function(){
         console.log('我可以快速下降');
             }
console.log(game);    //{name: '俄罗斯方块', up: ƒ, down: ƒ, Symbol(): ƒ, Symbol(): ƒ}
let youxi = {
       name:'狼人杀',
       [Symbol('say')]:function(){
            console.log('我可以发言');
               },
       [Symbol('zibao')]:function(){
            console.log('我可以自爆');
               }
      };
console.log(youxi);       //{name: '狼人杀', Symbol(say): ƒ, Symbol(zibao): ƒ}

2、Symbol的内置值

 除了定义自己使用的Symbol值以外,ES6还提供了11个内置的Symbol值,只想语言内部使用的方法。

Symbol.hasInstance当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法
Symbol.isConcatSpeadble对象的Symbol.isConcatSpreadable属性等于的是一个布尔值,表示该对象用于Array.prototype,concat()时,是否可以展开。
Symbol.unscopables该对象指定了使用with关键字时,哪些属性会被with环境排除。
Symbol.match当执行str.match(myObject)时,如果该属性存在,会调用它,返回该方法的返回值。
Symbol.replace当该对象被str.replace(myObject)方法调用时,会返回该方法的返回值。
Symbol.search当该对象被str.search(myObject)方法调用时,会返回该方法的返回值。
Symbol.split当该对象被str.split(myObject)方法调用时,会返回该方法的返回值。
Symbol.iterator对象进行for...of循环时,会调用Symbol.iterator方法,返回该对象的默认遍历器。
Symbol.toPrimitive该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。
Symbol.toStringTag在该对象上面调用toString方法时,返回该方法的返回值
Symbol.species创建衍生对象时,会使用该属性。
//1、Symbol.hasInstance
class Person {
       static[Symbol.hasInstance]() {
           console.log('我被用来检测类型了');
                  }
         }
let o = {};
console.log(o instanceof Person);    //false



//2、Symbol.isConcatSpeadble
const arr = [1, 2];
const arr2 = [3, 4, 5];
arr2[Symbol.isConcatSpreadable] = false;   //如果设置为false,则代表数组不可展开
console.log(arr.concat(arr2));             //[1, 2, Array(3)]

十一、迭代器

     迭代器(Iterator)是一种接口,为各种不同的数据结构提供同意的访问机制。任何数据结构只要部署iterator接口,就可以完成遍历操作。

(1)ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费

(2)原生具备iterator接口的数据(可用for of遍历)

        Array     Arguments    Set    Map    String   TypeArray    NodeList

(3)工作原理:

         ① 创建一个指针对象,指向当前数据结构的起始位置

         ② 第一次调用对象的next方法,指针自动指向数据结构的第一个成员

         ③ 接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员

         ④ 每调用next方法返回一个包含value和done属性的对象

     注:需要自定义遍历数据的时候,要想到迭代器。

const xiyou = ['唐僧','孙悟空','猪八戒','沙僧'];
//使用for..of 遍历
//for...of 保存的是键值(遍历数组)    for...in 保存的是键名(遍历对象、数组)

/*for (let v of xiyou){
            console.log(v);
         }*/

let iterator = xiyou[Symbol.iterator]();
 //调用对象的next方法
console.log(iterator.next());    //{value: '唐僧', done: false}
console.log(iterator.next());    //{value: '孙悟空', done: false}
console.log(iterator.next());    //{value: '猪八戒', done: false}
console.log(iterator.next());    //{value: '沙僧', done: false}
console.log(iterator.next());    //{value: undefined, done: true}
//迭代器应用-自定义遍历数组
const banji = {
        name:"终极一班",
        stus: [
            'xiaoming',
            'xiaoning',
            'xiaotian',
            'knight'
              ],
         [Symbol.iterator](){
               //索引变量
               let index = 0;
               let _this = this;
               return {
                   next:function(){
                       if (index < _this.stus.length) {
                           const result = {
                              value:_this.stus[index],
                              done:false
                            };
                       //下标自增
                        index++;
                        return result;
                         }else {
                             return {
                               value:undefined;
                               done:true
                               }
                           }
                         }
                      };
                  }
             }
//遍历这个对象,使用for...of遍历,返回的是这个属性数组里的每一个成员
for (let v of banji) {
    console.log(v);
        }

十二、生成器

生成器是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同

生成器是一种特殊的函数,来进行异步编程

function * gen(){
    //yield作为函数代码的分隔符,三个分隔符产生四个代码
    yield '一只没有耳朵';
    yield '一只没有尾巴';
    yield '真奇怪';
}
for (let v of gen){
    console.log(v);
 }
function * gen (arg) {
        console.log(arg);           //AAA
        let one = yield 111;
        console.log(one);           //BBB
        let two = yield 222;
        console.log(two);           //CCC
        let three = yield 333;
        console.log(three);         //DDD
     }
//执行获取迭代器对象
let iterator = gen('AAA');
console.log(itrator.next());             //{value: 111, done: false}
//next方法可以传入实参
console.log(itrator.next('BBB'));        //{value: 222, done: false}
console.log(itrator.next('CCC'));        //{value: 333, done: false}
console.log(itrator.next('DDD'));        //{value: undefined, done: true}

生成器实例

1、回调地狱

//1s 后控制台输出 111   2s后输出222   3s后输出333
setTimeout(() => {
    console.log(111);
      setTimeout(() => {
        console.log(222);
            setTimeout(() => {
              console.log(333);
       },3000);
    },2000);
 },1000);
function one() {
     setTimeout(() => {
         console.log(111);
         iterator.next();
      },1000)
}
function two() {
     setTimeout(() => {
         console.log(222);
         iterator.next();
      },2000)
}
function three() {
     setTimeout(() => {
         console.log(333);
         iterator.next();
      },3000)
}
function * gen() {
     yield one();
     yield two();
     yield three();
}

//调用生成器函数
let iterator = gen();
iterator.next();

2、 模拟获取

//模拟获取 用户数据 订单数据 商品数据
//先后顺序,依次获取

function getUsers() {
     setTimeout(() => {
       let data = '用户数据';
       //调用next方法,并且将数据传入
       iterator.next(data);
      }, 1000);
}

function getOrders() {
     setTimeout(() => {
       let data = '订单数据';
       iterator.next(data);
      }, 1000);
}

function getGoods() {
     setTimeout(() => {
       let data = '商品数据';
       iterator.next(data);
      }, 1000);
}

function* gen() {
    let users = yield getUsers();
    console.log(users);
    let orders = yield getOrders();
    console.log(orders);
    let goods = yield getGoods();
    console.log(goods);
}

//调用生成器函数
let iterator = gen();
iterator.next();

十三、Promise(面试常问)

   1、基础

    1. 1区别实例对象与函数对象

         ① 实例对象:new函数产生的对象,称为实例对象,简称为对象

         ② 函数对象:将函数作为对象使用时,称为函数对象

//括号的左边的函数, 点的左边是对象

function Fn() {                 //Fn是函数
     const fn = new Fn()        //此时Fn是构造函数   fn是实例对象,简称为对象
     console.log(Fn.prototype)  //Fn是函数对象
     Fn.blind({})               //Fn是函数对象
     $('#text')                 //jQuery函数
     $.get('/test')             //jQuery函数对象
}  

    1. 2 两种类型的回调函数

         1.2.1  同步回调

                   概念:立即执行,完全执行完了才结束,不会放入回调队列中

                   例子:数组遍历相关的回调函数/Promise的excutor函数

const arr = [1, 3, 5]
arr.forEach(item => {
    console.log(item);            //遍历的回调,同步回调函数,不会放入队列,一上来就要执行完
}) 
console.log('forEach()之后');

           1.2.2  异步回调

                   概念:不会立即执行,会放入回调队列中将来执行

                   例子:定时器回调、Ajax回调、Promise的成功|失败的回调

setTimeout(() => {
     console.log('timeout callback()');        //异步回调函数,会放入队列中将来执行
}, 0); 
console.log('setTimeout()之后');

         1.3  JS的error处理

           1.3.1 错误的类型

                    ① Error:所有错误的父类型

                    ② ReferenceError:引用的变量不存在

                    ③ TypeError:数据类型不正确的错误

                    ④ RangError:数据值不在其所允许的范围内

                    ⑤ SyntaxError:语法错误

           1.3.2 错误处理

                    ① 捕获错误:try...catch

try {
            let b
            console.log(b.xxx);
        } catch (error) {
            console.log(error); 
            //TypeError: Cannot read properties of undefined (reading 'xxx')
     }

                    ② 抛出错误:throw error 

 function something() {
            if (Date.now() % 2 === 1) {
                console.log('当前的时间为奇数,可以执行任务');
            } else { //抛出异常,由调用者来处理
                throw new Error('当前时间为偶数,无法执行任务')
            }
        }

//捕获处理异常
try {
    something()
    } catch (error) {
      alert(error.message)
    }

     2、 promise的理解和使用

             2.1   Promise是什么

                    ① 抽象表达:Promise是JS中进行异步编程的新的解决方案(旧的是纯回调形式)

                    ② 具体表达:

                  (1)从语法上来说:Promise是一个构造函数

                  (2)从功能上来说:Promise对象用来封装一个异步操作并可以获取其结果

            2.2   Promise的状态改变

                     ① pendding变为resolved

                     ② pedding变为rejected

                      说明:只有这2种,且一个promise对象只能改变一次

                                 无论变为成功还是失败,都会有一个结果数据

                                 成功的结果数据一般称为value,失败的结果数据一般称为reason

            2.3   Promise的基本流程

            2.4   Promise的基本使用         

//1、创建一个新的promise对象
        const p = new Promise((resolve, reject) => { //执行器函数
            //2、执行异步操作任务
            setTimeout(() => {
                const time = Date.now() //如果当前时间是偶数,就代表成功,否则代表失败
                    // 3、(1)如果成功了,调用resolve(value)
                if (time % 2 == 0) {
                    resolve('成功的数据, time =' + time)
                } else {
                    //    (2)如果失败了,调用rejecte(reason)
                    reject('失败的数据,time' + time)
                }
            }, 1000);

        })

        //4、
        p.then(
            value => { //接收得到成功的value数据      onResolved
                console.log('成功的回调', value);
            },
            reason => { //接收得到失败的reason数据   onRejected
                console.log('失败的回调', reason);
            }
        )

                2.5   为什么要用Promise ?

                      ① 使指定回调函数的方式更加灵活

             (1)旧的:必须在启动异步任务前指定

             (2)promise:启动异步任务  => 返回promise对象  => 给promise对象绑定回调函数 (甚至可以在异步任务启动后就指定)

// 1.1使用纯回调函数
        createAudioFileAsync(audioSettings, successCallback, failureCallback)
// 1.2使用promise
        const promise = createAudioFileAsync(audioSettings);
        setTimeout(() => {
            promise.then(successCallback, failureCallback);
        }, 3000);

                     ② 支持链式调用,可以解决回调地狱的问题

       (1)什么是回调地狱?回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调函数执行的条件(内层的结果为外层的参数)

      (2)回调函数的缺点?不便于阅读/不便于异常处理

      (3) 解决方案?promise链式调用

      (4)终极解决方案?async/await

//2.1回调地狱
        doSomething(function(result) {
            doSomethingElse(result, function(newResult) {
                doThirdThing(newResult, function(finalResult) {
                    console.log('Got the final result' + finalResult);
                }, failureCallback)
            }, failureCallback)
        }, failureCallback)

//2.2  使用promise的链式调用解决回调地狱
        doSomething().then(function(result) {
                return doSomethingElse(result)
            })
            .then(function(newResult) {
                return doThirdThing(newResult)
            })
            .then(function(finalResult) {
                lconsole.log('Got the final result' + finalResult)
            })
            .catch(failureCallback) //异常传透

//2.3  async/await :回调地狱的终极解决方案
 asnyc
        function request() {
            try {
                const result = await doSomething();
                const newResult = await doSomethingElse(result);
                const finalResult = await doThirdThing(newResult);
                console.log('Got the final result' + finalResult)
            } catch (error) {
                failureCallback(error)
            }
        }

                2.6   如何使用Promise ?

                  2.6.1 API

                  一、Promise构造函数:Promise(excutor){ }

                  (1)excutor函数:执行器(resolve,reject)=> { }

                  (2)resolve函数:内部定义成功时我们调用的函数value =>{ }

                  (3)reject函数:内部定义失败时我们调用的函数 reason =>{ }

                  说明:excutor会在Promise内部立即同步回调,一步操作在执行器中执行

                 二、Promise.prototype.then方法:(onResolved,onRejected)=>{ }

                        onResolved函数:成功回调函数   (value)=> { }

                        onRejected函数:失败回调函数   (reason)=> { }

                    说明:指定用于得到成功value的成功回调和用于得到失败reason的失败回调

                               返回一个新的promise对象

                 三、Promise.prototype.catch方法:(onRejected)=> { }

                        onRejected函数:失败的回调函数 (reason)=> { }

                    说明:then()的语法糖,相当于:then(undefined,onRejected)

                 四、Promise.resolve方法:(value)=> { }

                        value:成功的数据或promise对象

                   说明:返回一个成功/失败的promise对象

          

                 五、Promise.reject方法:(reason)=> { }

                        reason:失败的原因

                  说明:返回一个失败的promise对象

new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('成功的数据')
                    //只能执行一次reject('失败的数据')
            }, 1000)
        }).then(
            value => {
                console.log('onResolved()1', value);
            }
        ).catch(
            reason => {
                console.log('onRejected()', reason);
            }
        )
 const p1 = new Promise((resolve, reject) => {
            resolve(1)

        })
        const p2 = Promise.resolve(2);
        const p3 = Promise.reject(3);

        p1.then(value => {
            console.log(value)
        })
        p2.then(value => {
            console.log(value)
        })
        p3.catch(reason => {
            console.log(reason)
        })

              2.6.2 Promise的几个关键问题

              一、如何改变Promise的状态?

                     (1)resolve(value):如果当前是pendding就会变为resolved

                     (2)reject(reason):如果当前是pendding就会变为rejectd

                     (3)抛出异常:如果当前是pendding就会变为rejectd

 const p = new Promise((resolve, reject) => {
       // resolve(1) //promise变为resolved状态
      // reject(2) //promise变为rejected状态
      // throw new Error('出错了') //抛出异常,promise变为rejected失败状态,reason抛出的error
            throw 3
        })
        p.then(
            value => {},
            reason => {
                console.log('reason', reason); // 'reason', 3
            }
        )

              二、一个Promise指定多个成功/失败回调函数,都会调用嘛?

                     当Promise改变为对应状态时都会调用

             三、改变Promise状态和指定回调函数谁先谁后?

               (1)都有可能,正常情况下是先指定回调再改变状态,但也可以先改变状态再指定回调

               (2)如何先改状态再指定回调?

                        ① 在执行器中直接调用resolve()/ reject()

                        ② 延迟更长时间才能调用then()

               (3)什么时候才能得到数据?

                        ① 如果先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据

                        ② 如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据              

 //1、常规:先执行回调函数,后改变状态
        new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(1) //后改变状态(同时指定数据),异步执行回调函数
            }, 1000);
        }).then( //先指定回调函数,保存当前指定的回调函数
            value => {},
            reason => {
                console.log('reason', reason);
            }
        )
 //2、先改状态,后执行回调函数
        new Promise((resolve, reject) => {
            resolve(1) //先改变状态(同时指定数据)
        }).then( //后指定回调函数,异步执行回调函数
            value => {
                console.log('value', value);
            },
            reason => {
                console.log('reason', reason);
            }
        )

               四、Promise.then()返回的新的Promise的结果状态由什么决定?

                 (1)简单表述:由then()指定的回调函数执行的结果决定

                 (2)详细表述:

                        ① 如果抛出异常,新Promise变为rejected,reason为抛出的异常

                        ② 如果返回的是非Promise的任意值,新Promise变为resolved,value为返回的值

                        ③ 如果返回的是另一个新Promise,此Promise的结果就会成为新Promise的结果

             五、Promise如何串连多个操作任务

                   (1)Promise的then()返回一个新的Promise,可以开成then()的链式调用

                   (2)通过then的链式调用串连多个同步/异步任务

             六、Promise异常传透

                   (1)当使用Promise的then链式调用时,可以在最后指定失败的回调

                   (2) 前面任何操作出了异常,都会传到最后失败的回调中处理

             七、中断Promise链

                   (1)当使用Promise的then链式调用时,在中间中断,不再调用后面的回调函数

                   (2)办法:在回调函数中返回一个pendding状态的Promise对象

     3、自定义(手写)Promise

             3.1 定义整体结构(创建promise.js)

/*
自定义Promise函数模块:IFFE
*/
(function(window) {
    /*
    Promise构造函数
    executor:执行器函数(同步执行)
    */
    function Promise(excutor) {
    //resolve函数
        function resolve(data) {
         }

    //reject函数
        function reject (data) {
       }

    //同步调用执行器函数
     executor(resolve,reject);

    }


    /*
    Promise原型对象的then()
    1.指定成功和失败的回调函数
    2.函数返回一个新的promise对象
    */
    Promise.prototype.then = function(onResolve, onReject) {

    }


    /*
    Promise原型对象的catch()
    1.指定失败的回调函数
    2.函数返回一个新的promise对象
    */
    Promise.prototype.catch = function(onRejectd) {

    }


    /*
    Promise函数对象的resolve方法
    返回一个指定结果的成功promise
    */
    Promise.resolve = function(value) {

    }


    /*
    Promise函数对象的reject方法
    返回一个指定结果的失败promise
    */
    Promise.reject = function(reason) {

    }


    /*
    Promise函数对象的all方法
    返回一个promise,只有当所有promise都成功时,才成功,否则有一个失败,都失败
    */
    Promise.all = function(promises) {

    }


    /*
    Promise函数对象的race方法
    返回一个promise,其结果由第一个完成的promise来决定
    */
    Promise.race = function(promises) {

    }


    //向外暴露promise函数
    window.Promise = Promise
})(window)

             3.2 Promise构造函数的实现

             3.3 Promise.then()/ catch()的实现

             3.4 Promise.resolve() /  reject()的实现

//添加resolve方法
    Promise.resolve = function(value) {
        //返回promise对象
        return new Promise((resolve, reject) => {
            if (value instanceof Promise) {
                value.then(v => {
                    resolve(v);
                }, r => {
                    reject(r);
                })
            } else
            //状态设置成功、
                resolve(value)
        });
    }



    //添加reject方法
    Promise.reject = function(reason) {
        //返回promise对象
        return new Promise((resolve, reject) => {
            reject(reason);
        });

    }

             3.5 Promise.all()的实现

Promise.all = function(promises) {
        //返回结果为promise对象
        return new Promise((resolve, reject) => {
            //遍历
            for (let i = 0; i < promises.length; i++) {
                //声明变量
                let count = 0;
                let arr = [];
                //
                promises[i].then(v => {
                    //得知对象的状态是成功的
                    //每个promise对象都成功,才能执行resolve函数
                    count++;
                    //将当前promise对象成功的结果存入数组
                    arr[i] = v;
                    //判断
                    if (count === promises.length) {
                        resolve(arr);
                    }
                }, r => {
                    reject(r);
                })

            }
        });
    }

             3.5 Promise.all / race()的实现

Promise.race = function(promises) {
    return new Promise((resolve,reject)=>{
        for(let i = 0 ; i < promises.length;i++){
            promises[i].then(v=>{
             //修改返回对象值为成功
             resolve(v);
            },r=>{
            //次该范湖对象为失败
            reject(r);
            })
        }
    });
    }

          

   4、async与await

           4.1 async函数

               (1)函数的返回值为promise对象

               (2)promise对象的结果由async函数执行的返回值决定

//和then返回规则一样
        async function main() {
            //1、如果返回值是一个非promise类型的数据
            //  return 521;
            //2、如果返回值是一个promise对象
            return new Promise((resolve, reject) => {
                    // resolve('ok');
                    reject('error');
                })
                //3、抛出异常
            throw "oh no";
        };
        let result = main();
        console.log(result);

         4.2 await表达式

               (1)await右侧的表达式一般为promise对象,但也可以是其他的值

               (2)如果表达式是promise对象,await返回的是promise成功的值

               (3)如果表达式是其他值,直接将此值作为await的值

           注意:

               (1)await必须写在async函数中,但async函数中可以没有await

               (2)如果await的promise失败了,就会抛出异常,需要通过try...catch捕获处理          

//await必须写在async函数中,但async函数中可以没有await
        // await 10; //Uncaught SyntaxError: await is only valid in async functions and the top level bodies of modules
        async function main() {
            let p = new Promise((resolve, reject) => {
                // resolve('ok');
                reject('error');
            });
            //1、右侧为promise的情况
            // await返回值是promise成功的值
            let res = await p;
            console.log(res); //ok
            //2、右侧为其他类型的数据
            //直接将此值作为await的值
            let res2 = await 20;
            console.log(res2); //20
            //3、如果promise是失败的状态
            try {
                let res3 = await p;
            } catch (e) {
                console.log(e);  //error
            }

        }
        main();

十四、Set

ES6提供了新的数据结构Set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了iterator接口,所以可以使用扩展运算符和for...of进行遍历,集合的属性和方法:

(1)size   返回集合的元素个数

(2)add   增加一个新元素,返回当前集合

(3)delete 删除元素,返回boolean值

(4)has  检测集合中是否包含某个元素,返回boolean值。

//声明一个set
        let s = new Set();
        let s2 = new Set(['大事', '小事', '没事']);
        console.log(s, typeof s); 
        //Set(0) {size: 0}[[Entries]]无属性size: 0[[Prototype]]: Set 'object'
        console.log(s2, typeof s2); 
        //Set(3) {'大事', '小事', '没事'} 'object'

        //1、元素个数
        console.log(s2.size); //3
        //添加新的元素
        s2.add('喜事');
        console.log(s2); //Set(4) {'大事', '小事', '没事', '喜事'}
        //删除元素
        s2.delete('喜事');
        console.log(s2);
        //2、检测
        console.log(s2.has('大事')); //true
        //3、清空
        s2.clear();
        console.log(s2); //Set(0) {size: 0}


        //遍历
        for (let v of s2) {  
            console.log(v);
        }

 案例:

   let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1];
        //1、数组去重
        let result = [...new Set(arr)];
        console.log(result);

        //2、交集
        let arr2 = [4, 5, 6, 5, 6];
        //filter创建一个数组,符合条件的都放进去(过滤器)
        let result = [...new Set(arr)].filter(item => {
            let s2 = new Set(arr2);  //4.5.6
            if(s2.has(item)){
                return true;
            }else {
                return false;
            }
        }); 

        //简写
        let result = [...new Set(arr)].filter(item => new Set(arr2).has(item));
        console.log(result); //[4,5]


        //3、并集
        let union = [...new Set([...arr, ...arr2])];
        console.log(union);   //合并arr和arr2数组   [1, 2, 3, 4, 5, 6]

        //4、差集
        //用arr和arr2比较
        let diff = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)));  

十五、Map

ES6提供了Map数据结构。它类似于对象,也是键值对的集合。但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当做键。Map也实现了iterator接口,所以可以使用扩展运算符和for...of进行遍历。Map的属性和方法:

(1)size  返回Map的元素个数

(2)set   增加一个新元素,返回当前Map

(3)get   返回键名对象的键值

(4)has   检测Map中是否包含某个元素,返回Boolean值

(5)clear  清空集合,返回undefined

十六、class类

function Phone() {

        }
        // Phone是函数对象,属于类,不属于实例对象
        Phone.name = '手机';
        Phone.change = function() {
            console.log('我可以改变世界');
        }
        Phone.prototype.size = '5.5inch';
        //nokia是实例对象
        let nokia = new Phone();
        console.log(nokia.name); //undefined
        console.log(nokia.size); //5.5inch
class Phone {
            //静态属性  static标注的属性和方法,属于class类,不属于实例对象vivo
            static name = '手机';
            static change() {
                console.log('手机真好玩');
            }
        }
        let vivo = new Phone();
        console.log(vivo.name); //undefined
        console.log(Phone.name); //手机

十七、数值扩展

          1、Number.EPSILON是JavaScript表示的最小精度

               EPSILON属性的值接近于2.2204460492503130808472633361816E-16(主要用作在浮点数上)

function equal(a, b) {
            if (Math.abs(a - b) < Number.EPSILON) {
                return true;
            } else {
                return false;
            }
        }
        console.log(0.1 + 0.2 === 0.3);      //false
        console.log(equal(0.1 + 0.2, 0.3));  //true

          2、二进制和八进制

let b = 0b1010; //二进制
        let o = 0o777; //八进制
        let d = 100; //十进制
        let x = 0xff; //十六进制

        console.log(b); //10
        console.log(d); //100

          3、Number.inFinite 检测一个数值是否为有限数

console.log(Number.isFinite(100)); //true
console.log(Number.isFinite(100 / 0)); //false
console.log(Number.isFinite(Infinity));//false

          4、Number.isNaN 检测一个数值是否为NaN

console.log(Number.isNaN(123)); //false

         5、Number.parseInt / Number.parseFloat字符串转整数

 console.log(Number.parseInt('5201314love')); //5201314
 console.log(Number.parseFloat('3.1415926神奇'));//3.1415926

        6、Number.isInteger 判断一个数是否为整数

console.log(Number.isInteger(5));   //true
console.log(Number.isInteger(2.55));//false

        7、Math.trunc 将数字的小数部分抹掉

console.log(Math.trunc(3.5)); //3

        8、Math.sign 判断一个数到底为正数、负数还是零

console.log(Math.sign(100));  //1
console.log(Math.sign(0));    //0
console.log(Math.sign(-250));  //-1

十八、对象扩展

       1、Object.is 判断两个值是否完全相等

 

 console.log(Object.is(120, 121)); //作用和===很像
 console.log(Object.is(NaN, NaN)); //true
 console.log(NaN === NaN); //false  

 

       2、Object.assign对象的合并

const config1 = {
            hose: 'localhost',
            port: 3306,
            name: 'root',
            pass: 'root',
            text: 'test',
        };
        const config2 = {
            host: 'http://baidu.com',
            port: 33060,
            name: 'baidu',
            pass: 'iloveyou'
        };
        console.log(Object.assign(config1, config2));
   //{hose: 'localhost', port: 33060, name: 'baidu', pass: 'iloveyou', text: 'test', …}
   // hose: "localhost"
   // host: "http://baidu.com"
   // name: "baidu"
   // pass: "iloveyou"
   // port: 33060
   // text: "test"
   // [[Prototype]]: Object

 

       3、Object.setPrototypeOf  / Object.getPrototypeOf

const school = {
       name: 'beida'
        };
const city = {
        xiaoqu: ['北京', '上海', '深圳']
        };
Object.setPrototypeOf(school, city);   
console.log(Object.getPrototypeOf(school));   //{xiaoqu: Array(3)}
console.log(school);   //{name: 'beida'}

十九、模块化

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

1、模块化的好处

(1)防止命名冲突

(2)代码复用

(3)高维护性

2、模块化规模产品

ES6之前的模块化规范有:

(1)CommonJs    =>    NodeJs、Browserify

(2)AMD              =>    requireJS

(3)CMD             =>   seaJS

3、ES6模块化语法

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

(1)export命令用于规定模块的对外接口

(2)import命令用于输入其他模块提供的功能

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值