js面试三之ES6

一、变量相关(let、var、const、function)

  • let和const都能够声明块级作用域,用法和var是类似的,let的特点是不会变量提升,而是被锁在当前块中。
  • const 声明的就是常量,保证指针是固定的;声明并赋值

let、const 与 var 的区别(五个):

1.重复声明— var 允许重复声明,let、const 不允许

2.变量提升—把当前作用域中所有带var、function关键字的进行提前的声明和定义 【预解析】

  • var 会提升变量的声明到当前作用域的顶部; let、const 不存在变量提升.

3.块级作用域

var 没有块级作用域,let/const 有块级作用域。若果在独立的{}(不含函数的花括号)内用let/const声明变量会形成块级作用域,不让外界访问。

4.暂时性死区

  • 只要作用域内存在 let、const,它们所声明的变量或常量就自动“绑定”这个区域,不再受到外部作用域的影响,let、const 存在暂时性死区
var name='jack';
{
 name='bob';
 let name;    //Uncaught ReferenceError: Cannot access 'name' before initialization
}
复制代码

5.window 对象的属性和方法:

全局作用域中,var 声明的变量,以及通过 function 声明的函数,会自动变成 window 对象的属性或方法,let、const 不会。

二.模板字符串

  • 模板字符串用反引号表示,可以在里面直接使用字符串,还可以使用变量、表达式通过${}注入
  • 模板字符串中,所有的空格、换行或缩进都会被保留在输出之中

三.箭头函数

1.箭头函数的结构

      const/let 函数名 = 参数 => 函数体
      const add = () => {};
复制代码

2.箭头函数简化—- 单个参数可以省略圆括号,单行函数体可省略花括号及return

3.this 指向

1.全局作用域中的 this 指向
     console.log(this); // window

2.一般函数(非箭头函数)中的 this 指向
      // 'use strict';
      function add() {
        console.log(this); 
        // 严格模式就指向 undefined
        // undefined->window(非严格模式下)
      }
      add();
     
     
3.点击事件的this指向
      document.onclick = function () {
         console.log(this);  //this指向document
       };
   
      // 只有在函数调用的时候 this 指向才确定,不调用的时候,不知道指向谁
      // this 指向和函数在哪儿调用没关系,只和谁在调用有关
      // 没有具体调用对象的话,this 指向 undefined,在非严格模式下,转向 window
      
4.箭头函数中的 this 指向
    箭头函数没有自己的 this,所以会从上级上下文一层一层的往外找this,最后找到window,他的this指向window
复制代码

4.不适用箭头函数的场景

  • 1.箭头函数不能作为构造函数
  • 2.需要 this 指向调用对象的时候,不能用箭头函数
      document.onclick = function () {
        console.log(this);
      };
      document.addEventListener(
        'click',
        () => {
          console.log(this); //window
        },
        false
      );
    复制代码
  • 3.需要使用 arguments 的时候,不能用箭头函数,箭头函数中没有 arguments

四.解构赋值

解构赋值是指解析某一数据的结构,将我们想要的东西提取出来,赋值给变量或常量;

4.1 数组解构赋值(索引值相等和模式匹配)

数组解构赋值非常简单,遵循模式匹配原则和索引值相同的进行赋值就可以了,如果不需要结构的用逗号跳过即可。

4.1.1 默认值,没有解构出来,就用默认值(惰性求值)

只有当一个数组成员严格等于(===)undefined 时,对应的默认值才会生效

[a = 1, b = 2] = [3, undefined];
//a=3,b=2
复制代码

4.1.2 数组解构赋值应用

  • 1.常见的类数组的解构赋值

  • 2.函数参数的解构赋值

  • 3.交换变量的值

4.2 对象解构赋值(模式匹配和属性名相同)

//属性名相同的完成赋值,可以取别名
      const { age, username: uname } = { username: 'Alex', age: 18 };
      console.log(age, uname);//解构赋值之后再赋值给uname
复制代码
  • 默认值和数组的一样

  • 如果将一个已经声明的变量用于对象的解构赋值,整个赋值需在圆括号中进行,防止被当成块级作用域

     let x = 2;
    ({ x } = { x: 1 });
    console.log(x);    //1
    复制代码

对象解构赋值的应用

  • 1.函数参数的解构赋值
     const PersonInfo = (user) => console.log(user.username, user.age);
     PersonInfo(({ age, username: username } = { username: "alex", age: 18 })); //alex 18 使用了解构后的值
     
     const person = ({ age = 0, username = "ZhangSan" }) =>console.log(username, age);
     person({}); //ZhangSan 0  使用了默认值
     person({ username: "alex", age: 18 }); //alex 18 使用了解构后的值
复制代码
  • 2.复杂的嵌套

4.3 字符串的解构赋值

  • 字符串可以按照数组形式的解构赋值
  • 字符串可以按照类数组对象形式的解构赋值(可以按照索引值和length)

五.对象字面量增强

5.1 属性和方法简写

在对象中属性名和值相等可以简写;方法可以直接写,也不用function声明

const age=18
const obj={
            age,
            fn(){}
 }
复制代码

5.2.方括号语法增强–属性名可以写变量啦

1.方括号语法可以写在对象字面量中

      const name = 123;
      const obj = {
        ["age"]: 18,
        [name]: "蔡徐坤",
      };
      console.log(obj);//{123: "蔡徐坤", age: 18}
复制代码

六、函数参数默认值-可以给形参设置默认值,不传参则使用默认值

七.剩余参数与展开运算符

剩余/扩展运算符同样也是ES6一个非常重要的语法,使用3个点(…),后面跟着一个含有iterator接口的数据结构

7.1 剩余参数–参数变数组

剩余参数可以将多余的实参组成一个数组,可以在函数形参的最后一个位置通过...args设置,

7.1.1 箭头函数的剩余参数

对于箭头函数来说,没有 arguments,使用剩余参数替代 arguments 获取实际参数,此时不能省略圆括号;

const add = (...args) => {
console.log(args);
};
add(1, 2);
复制代码

7.1.2 剩余参数的应用

  • 1.完成 add 函数
  • 2.与解构赋值结合使用

7.2 数组展开运算符—将一个数组转为用逗号分隔的参数序列,主要用于函数调用。

console.log(Math.min(...[3, 1, 2]));
复制代码

7.2.1 替代函数的 apply 方法

由于扩展运算符可以展开数组,所以不再需要apply方法,将数组转为函数的参数了,apply方法第二个参数是数组实参。

7.2.2 数组展开运算符的应用

  • 1.复制数组(深拷贝)
       const a = [1, 2];
       const c = [...a];
       a[0] = 3;
       console.log(a);//[3,2]
       console.log(c);//[1,2]
复制代码
  • 2.合并数组(浅拷贝)
const arr1 = ['a', 'b'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];

// ES5 的合并数组
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]

// ES6 的合并数组
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]
复制代码
  • 3.字符串转为数组
       console.log([...'alex']);//['a','l','e','x']
       console.log('alex'.split(''));//es6之前
复制代码
  • 4.常见的类数组转化为数组
    4.1 arguments
       function func() {
         console.log([...arguments]);
       }
       func(1, 2);

    4.2 NodeList
      console.log([...document.querySelectorAll('p')]);
复制代码
    1. 实现了 Iterator 接口的对象

任何定义了遍历器(Iterator)接口的对象(参阅 Iterator 一章),都可以用扩展运算符转为真正的数组。

let nodeList = document.querySelectorAll('div');
let array = [...nodeList];
复制代码

7.3 对象展开运算符的基本用法

对象的扩展运算符(…)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。

1. 展开对象(深拷贝对象)

  • 对象不能直接展开,必须在 {} 中展开
  • 对象的展开:把属性罗列出来,用逗号分隔,放到一个 {} 中,构成新对象
      const apple = {
        color: "红色",
        shape: "球形",
        taste: "甜",
      };
      const Ob = { ...apple };
      console.log(Ob);
      console.log(Ob === apple); //false
复制代码

2.合并对象,后面的同属姓名会覆盖前面的

3. 用户参数和默认参数合并,默认参数写前面,用户参数写后面

4.注意事项—如果展开的不是对象,则会自动将其转为对象,再将其属性罗列出来,类数组对象

八.Symbol唯一值

ES6新规定的Symbol(符号)是原始值,且符号实例唯一、不可变的,它的用途是确保对象属性使用唯一标识符。

//1.需要使用Symbol()函数初始化
 let name1 = Symbol('liming');
 let name2 = Symbol('liming');
 console.log(name1 == name2);  //false
 
// 希望能够多次使用同一个symbol值
 let name1 = Symbol.for('name'); //检测到未创建后新建
 let name2 = Symbol.for('name'); //检测到已创建后返回
 console.log(name1 === name2); // true
 
//能够访问的方法:Object.getOwnPropertySymbols.该方法会返回一个数组,成员是当前对象的所有用作属性名的Symbol值。

 let id = Symbol("id");
 let obj = {
  [id]:'symbol'
 };
let array = Object.getOwnPropertySymbols(obj);
 console.log(array); //[Symbol(id)]
 console.log(obj[array[0]]);  //'symbol'
复制代码

九.Set 和 Map 数据结构

9.1 Set数据结构—类似于数组( value = key),但没有重复的值。

Set 构造函数的参数–可以接受一个数组(或者具有 iterable 接口的其他数据结构如字符串、arguments、NodeList、Set)作为参数,用来初始化。

      var s2 = new Set([1, 2, 3]); 
      console.log(s2, typeof s2);   //Set(3) {1, 2, 3} "object"

// 1. add添加成员(可以连写)
      const s = new Set();
      s.add(1).add(2).add(2);
      console.log(s);//{1,2}
      
// 2. has判断是否有某个成员
      const s = new Set(["ccc", "ssss", "dddd"]);
      console.log(s.has("dddd")); //true
      
// 3.delete删除某个成员
      s.delete("dddd");
      
// 4. clear全部清除
      s.clear();
      
// 5.属性size--用来获取成员个数,相当于length

// 6.遍历操作(四个方法),Set 中 value = key
    // Set.prototype.keys():返回键名的遍历器
    // Set.prototype.values():返回键值的遍历器
    // Set.prototype.entries():返回键值对的遍历器
    /*  
        Set.prototype.forEach():使用回调函数遍历每个成员,有两个参数,
        第一个是回调函数,第二个是改变this指向
    */
        const s = new Set(["蔡徐坤", "李易峰", "易烊千玺"]);
        s.forEach(function (value, key, set) {
          console.log(this);//document
          console.log(value, key, set === s);//蔡徐坤 蔡徐坤 true
       }, document);
      // 按照成员添加进集合的顺序遍历
复制代码

Set 应用

① 数组或字符串去重时
② 不需要通过下标访问,只需要遍历时
③ 为了使用 Set 提供的方法和属性时(add delete clear has forEach size 等)

1.数组去重

  console.log([...new Set([1, 2, 1])]);
复制代码

2.字符串去重 ‘abbacbd’;
把字符串用Set方法变成去重后对象,再把对象转化成数组,用数组的join方法转化成字符串

       const s = new Set('abbacbd');
       console.log(s);//{'a','b','c','d'}
       console.log([...s].join(''));
       console.log(s);

       //一行搞定
       console.log([...new Set('abbacbd')].join(''));
复制代码

3.存放 DOM 元素

 <p>1111</p>
 <p>22222</p>
 <p>3333</p>
      // for()
      const s = new Set(document.querySelectorAll('p'));
      console.log(s);
      s.forEach(function (elem) {
        console.log(elem);
        elem.style.color = 'red';
        elem.style.backgroundColor = 'yellow';
      });
复制代码

十.Iterator 和 for…of 循环

10.1 Iterator遍历器(迭代器)

Iterator 是 ES6 引入的一种新的遍历机制,凡是有Iterator接口的数据结构都是可遍历的,可以通过for...of...来遍历.

10.2 为什么需要 Iterator 遍历器–for..of 来遍历

我们之前的遍历方法是:

  • 遍历数组:for 循环和 forEach 方法
  • 遍历对象:for in 循环

而 Iterator 遍历器是一个统一的遍历方式,使用 Iterator 封装好的 for..of 来遍历,不管是数组还是对象都可以遍历

10.3 原生可遍历(有Iterator接口)

  • 数组
  • 字符串
  • Set
  • Map
  • arguments
  • NodeList(一般用querySelectorAll获得的)
  • 一般的对象可以用for … in遍历,也可以给他添加一个Symbol.iterator然后用for … of 遍历

10.2.1 for…of 遍历数组

const arr = [1, 2, 3];
//1.遍历出索引值arr.keys() 得到的是索引的可遍历对象
      for (const key of arr.keys()) {
          console.log(key);
       }
//2.遍历出值arr.values() 可以等价于arr
//3遍历出[index,value]用arr.entries() 得到的是索引+值组成的数组的可遍历对象
复制代码

10.2.2 for…of 遍历普通对象Object.entries(obj)

十一.Es6新增方法

11.1 Es6字符串新增方法(3个)

1. includes()判断字符串中是否含有某些字符

//判断字符串
console.log('abc'.includes('a', 0));//true
1.第一个参数------表示是否包含该值
2.第二个参数----- 表示开始搜索的位置,默认是 0,index

//判断数组
 arr = ["name", 2, 3, 4, 5, 6, 7, 8];
 console.log(arr.includes("name"));//true
复制代码
应用:给url添加参数,判断url有没有问号,有问号说明有key=value,再添加就直接添加连接符&key=value

2.padStart() 和 padEnd()在字符串本身的头部或尾部补全字符串长度

      console.log("abc".padStart(10, "0123456789")); //0123456abc
      console.log("abc".padEnd(10, "0123456789")); //abc0123456
      //  第一个参数表示补全后的字符串长度(有几个),第二个参数是要用到的元素补全字符串
      // 如果省略第二个参数,默认使用空格补全长度
复制代码
应用—-显示日期格式

3.trimStart() 和 trimEnd()清除字符串的首或尾空格

       const s = '  a b c  ';
       console.log(s);
       console.log(s.trimStart());
       console.log(s.trimEnd());
复制代码
应用-表单验证提交

11.2 Es6数组新增方法(三个)

1.includes()

  • 判断数组中是否含有某个成员
  • 第二个参数表示搜索的起始位置,默认值是 0
应用-数组去重
      const arr = [];
      for (const item of [1, 2, 1]) {
        if (!arr.includes(item)) {
          arr.push(item);
        }
      }
      console.log(arr); //[1,2]
复制代码

2.Array.from()将类数组对象或可迭代对象转化为数组

  • 一个类数组对象必须含有 length 属性,且元素属性名必须是数值或者可转换为数值的字符。

  • 可迭代对象(数组、字符串、Set、Map、NodeList、arguments)。

  • 元素属性名不为数值且无法转换为数值,返回长度为 length 元素值为 undefined 的数组

  • 第一个参数—能被转化的数据对象。

  • 第二个参数—作用类似于数组的 map 方法,用来对每个元素进行处理,将处理后的值放入返回的数组

  • 第三个参数–第二个参数为一般回调函数时,第三个参数可以改变 this 指向

      let a = { 
          0: "aaa", 
          1: "bbb", 
          2: "cccc", 
          3: "ddd", 
          4: "eeee", 
          length: 5 
        };
      let array1 = Array.from(a, (value) => value + "你真帅");
      console.log(array1); // ["aaa你真帅", "bbb你真帅", "cccc你真帅", "ddd你真帅", "eeee你真帅"]
复制代码

3.find(callback)返回元素 和 findIndex()返回索引

find():find()返回第一个匹配到的元素

  • 1.find()方法依次对数组项中执行回调函数(条件判断语句),直至条件为 true,就返回该项(元素),找不到的话就返回undefined。
  • 2.callback函数带有3个参数:当前元素的值、当前元素的索引,以及数组本身。
     var num = [10, 20, 30, 40, 50, 60, 70, 80, 90];
     var newNum1 = num.find((item, index) => {
       return item > 40;
     });
     console.log(newNum1); //50
复制代码

findIndex()用法结构类似,但是,返回数组中第一个满足条件的索引(从0开始), 不满足返回-1;

应用-筛选数据
      const students = [
        {
          name: "张三",
          sex: "男",
          age: 16,
        },
        {
          name: "李四",
          sex: "女",
          age: 22,
        },
        {
          name: "王二麻子",
          sex: "男",
          age: 32,
        },
      ];
      console.log(students.find((value) => value.sex === "男"));
      console.log(students.findIndex((value) => value.sex === "女"));
复制代码

11.3 Es6对象新增方法(2个)

1.Object.assign()合并对象

  • Object.assign(目标对象, 源对象 1,源对象 2,…): 目标对象
  • Object.assign 直接合并到了第一个参数中,返回的就是合并后的对象
应用–合并默认参数和用户参数
      const logUser = (userOptions) => {
        const DEFAULTS = {
          username: "ZhangSan",
          age: 0,
          sex: "male",
        };
        const options = Object.assign({}, DEFAULTS, userOptions);
        console.log(options);
      };
      logUser();
复制代码

2.Object.keys()、Object.values() 和 Object.entries()

  • 数组的 keys()、values()、entries() 等方法是实例方法,返回的都是 Iterator
  • 对象的 Object.keys()、Object.values()、Object.entries() 等方法是构造函数方法,返回的是数组
      const person = {
        name: "Alex",
        age: 18,
      };

      console.log(Object.keys(person)); //['name',"age"]
      console.log(Object.values(person));//["Alex", 18]
      console.log(Object.entries(person)); //二维数组  [["name", "Alex"],["age", 18]]
复制代码
应用-和for…of…一起遍历对象
      obj = { name: "蔡徐坤", age: "18", hobby: ["唱歌", "写歌", "跳舞"] };
      console.log(Object.entries(obj));

      for (key of Object.entries(obj)) {
        console.log(key[0], key[1]);
      }
复制代码

十二.Promise对象

  • Promise是ES6中新增的异步编程解决方案, 他是一个构造函数,在代码中通过new Promise()生成一个实例对象。精髓是通过状态调用用对应的回调函数。
  • Promise对象可以将异步操作以同步流程来表示, 避免了回调函数层层嵌套(回调地狱)。

12.1 基本使用

第一步:创建一个Promise实例对象,并传入执行器函数,执行器函数会同时执行

//Promise是一个构造函数
let p = new Promise(executor)
复制代码

第二步:executor执行器函数接受两个函数参数,resolve和reject,这两个函数是改变Promise状态的;状态一旦改变既不可逆。

  1. pending: 初始状态。
  2. fulfilled(resolved): 只要调用resolve函数的状态, 表示操作成功。
  3. rejected: 只要调用rejected函数,表示操作失败。
  4. 状态成功或失败都会调用对应成功或失败的回调函数。.then(success(){},failed(){})
let p=new Promise((resolve,reject)={
  /* 
  执行器函数里面,一般存放的都是我们即将要处理的异步任务(比如网络请求),任务成功我们执行resolve吧数据传出去, 任务失败我们执行reject(当然写同步的也可以),之后根据状态就可以调用原型里面的三个方法
  */
})
复制代码

12.2 Promise.prototype.then()方法的使用(可以多次使用)

  • then 方法接收两个函数为参数,第一个参数是 Promise 执行成功时的回调,第二个参数是 Promise 执行失败时的回调,两个函数只会有一个被调用。

  • then()方法执行后返回的是一个新的 Promise 对象,这个promise的状态由then里面执行的回调函数的返回值决定,返回值是非promise对象,他的状态就是成功的,返回值是promise对象,状态就由这个对象决定

// Promise对象的结构;
{
 [[PromiseState]]: "fulfilled"
//第一个由resolve或reject决定,后面执行的then返回的对象状态由当前函数返回值决定
         
[[PromiseResult]]: "222"
//结果就是当前Promise对象调用then之后return的值,
}      
复制代码
  • 可以通过上一个promise对象的then方法给下一个promise对象的then方法传递参数,传递的参数通过return返回给下一个promise对象的then方法。
  • 如果第一次是reject(),会调用失败的回调函数,并且返回一个新的promise状态是成功的,那么我们想要让他状态失败怎么搞,在调用回调函数里面抛出错误throw new Error(err);

结论:
执行reject()的后果:

让当前Promise对象状态变为失败,不影响后面的,后面的都为成功;

只要调用过程用到了reject(),就再也不能获取原始的数据了;

前面使用reject之后,若果想要后面也跟着状态变为失败,就要在reject()对应的失败函数里面抛出错误语句: throw new Error(err);

若果你想要改变当前调用then返回的Promise结果,就需要在当前then里面添加return返回想要的结果。

无论是在上一个promise对象成功的回调还是失败的回调传递的参数, 都会传递给下一个promise对象成功的回调。

12.2 Promise.prototype.catch()方法的使用

  • .catch()专门监听失败的回调
  • 如果需要分开监听,用.then().catch()方法使用链式编程,promise的状态如果是失败, 但是没有对应失败的监听就会报错
  • 和then方法第二个参数的区别在于, catch方法可以捕获上一个promise对象then方法(也包括成功的回调的方法)中的异常。

js异常处理

利用try{}catch{}来处理异常可以保证程序不被中断, 也可以记录错误原因以便于后续优化迭代更新。

try {
  可能遇到的意外的代码
}
catch(e) {
  捕获错误的代码块
}
复制代码

catch的特点:

  • (1)和then一样, 在修改promise状态时, 可以传递参数给catch方法中的回调函数;
  • (2)和then一样, 同一个promise对象可以多次调用catch方法, 当该promise对象的状态时所有catch方法都会被执行.
  • (3)和then一样, catch方法每次执行完毕后会返回一个新的promise对象
  • (4) 和then方法一样, 上一个promise对象也可以给下一个promise成功的传递参数。但是,无论是在上一个promise对象成功的回调还是失败的回调传递的参数, 都会传递给下一个promise对象成功的回调。
  • (5).和then一样, catch方法如果返回的是一个Promise对象, 那么会将返回的Promise对象的执行结果中的值传递给下一个catch方法。
  • (6) .和then方法第二个参数的区别在于, catch方法可以捕获上一个promise对象then方法中的异常。

12.3 Promise.all()方法的使用

参数:

    1. all方法接收一个数组.
    1. 如果数组中有多个Promise对象,只有都成功才会执行then方法,并且会按照添加的顺序, 将所有成功的结果重新打包到一个数组中返回给我们。
    1. 如果数组中不是Promise对象, 那么会直接执行then方法

返回:

  • 1.all方法会返回一个新的Promise对象

  • 2.会按照传入数组的顺序将所有Promise中成功返回的结果保存到一个新的数组返回

  • 3.数组中有一个Promise失败就会失败, 只有所有成功才会成功

  • 应用场景: 批量加载, 要么一起成功, 要么一起失败

12.4 Promise.race()方法的使用

  • 1.race方法接收一个数组,
  • 2.如果数组中有多个Promise对象, 谁先返回状态就听谁的, 后返回的会被抛弃
  • 3.如果数组中不是Promise对象, 那么会直接执行then方法
  • 应用场景: 接口调试, 超时处理

给超时函数和加载函数均包装一个promise对象,然后把这个对象写入race里面,紧接着写处理函数,5s之内没有获取资源,就直接超时处理

12.5 Promise.resolve()和Promise.reject()方法的使用

Promise.resolve()返回一个成功的Promise对象

      p = Promise.resolve("success");
      console.log(p);

      /*
      [[PromiseState]]: "fulfilled"
      [[PromiseResult]]: "success"
      */
复制代码

Promise.reject()返回一个失败的Promise对象

      p = Promise.reject("failed");
      p.catch((err) => console.log(err));
      console.log(p);

      /*
       [[PromiseState]]: "rejected"
       [[PromiseResult]]: "failed"
      */
复制代码

Promise封装网络请求放到网络那一块

总结:Promise如何发挥作用?

  • 买菜(20分钟)–>做饭(30分钟)–>送饭(十分钟)–>通知;都是耗时的异步任务
  • 搞很多函数(买菜函数、做饭函数、送饭函数、亲一个函数),均接受resolve函数参数,并在定时器里面执行resolve把做好了的事情发过去。
new Promise(买菜).then((买好的菜)=>{
    return new Promise(做饭);
}).then((做好的饭)=>{
    return new Promise(送饭);
}).then((送饭结果)=>{
    老婆亲一个();
}).catch(err=>throw new Error(err))
复制代码
//写好任务计划表
function 买菜(resolve,reject) {
    setTimeout(function(){
        resolve(['西红柿''鸡蛋''油菜']);
    },3000)
}
function 做饭(resolve, reject){
    setTimeout(function(){
        //对做好的饭进行下一步处理。
        resolve ({
            主食: '米饭',
            菜: ['西红柿炒鸡蛋''清炒油菜']
        })
    },3000) 
}
function 送饭(resolve,reject){
    //对送饭的结果进行下一步处理
    resolve('老婆的么么哒');
}
function 电话通知我(){
    //电话通知我后的下一步处理
    给保姆加100块钱奖金;
}

//开始做任务
// 告诉保姆帮我做几件连贯的事情,先去超市买菜
new Promise(买菜)
//用买好的菜做饭
.then((买好的菜)=>{
    return new Promise(做饭);
})
//把做好的饭送到老婆公司
.then((做好的饭)=>{
    return new Promise(送饭);
})
//送完饭后打电话通知我
.then((送饭结果)=>{
    电话通知我();
})
复制代码
  • 请一定要谨记:如果我们的后续任务是异步任务的话,必须return 一个 新的 promise 对象。
  • 如果后续任务是同步任务,只需 return 一个结果即可。
  • 我们上面举的例子,除了电话通知我是一个同步任务,其余的都是异步任务,异步任务 return 的是 promise对象。

十三.async 函数

async和await是Promise的语法糖
async是对函数的一个修饰,使一个函数返回Promise实例。
await是等待一个Promise实例成功后执行

  • 1.给函数加上一个async修饰符之后,函数执行的结果是一个成功的promise对象,我们可以直接在函数执行语句后面用then。
      async function foo() {
        //1.返回成功的
        //return Promise.resolve();
        return 1;

        // 2.返回失败的
        // return Promise.reject();
        // throw new Error("我错了");
      }
 
      foo().then((res) => {
        console.log(res); //1
      });
复制代码
  • 2.await只能在async函数里面执行,否则会报错,它的含义是等待一个promise实例成功后执行。
面试题:编写一个 sleep 函数,让其等待 1000ms 后再去做其他事情?
  • 方案一:用定时器
  • 方案二:函数返回值为Promise对象
      function sleep(interval = 5000) {
        return new Promise((resolve) => {
          setTimeout(resolve, interval);
        });
      }
      sleep(2000).then(() => {
        console.log("我在2000ms之后执行");
      });
复制代码
  • 方案三:利用await语句
      function sleep(interval = 1000) {
        return new Promise((resolve) => {
          setTimeout(resolve, interval);
        });
      }
      (async function () {
        //买菜需要八秒
        await sleep(8000);
        //菜卖回来了通知我
        console.log("我在1000ms之后执行");
        //做饭需要两秒
        await sleep(2000);
        //饭做好了通知我
        console.log("我在2000ms之后执行");
        //吃饭需要5s
        await sleep(5000);
        //吃完饭了通知我
        console.log("我在5000ms之后执行");
      })();
复制代码

十四.Module 的语法

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

变量或函数加载

  • 若果要输出变量或函数,直接在其最前面加上export,而使用其他模块中变量时,则使用import引入
//1.export 设置对外接口
export var name='蔡徐坤'
export function multiply() {}
export { firstName, lastName, year }

//import 命令加载这个模块(对外对内接口名相同)。
//import 命令输入的变量都是只读的,不允许在加载模块的脚本里面,改写接口。
//import 命令具有提升效果,会提升到整个模块的头部,首先执行。
import { firstName, lastName, year } from './profile.js'
复制代码

模块的整体加载—export default 命令

为了给用户提供方便,让他们不需要知道所要加载的变量名或函数名,就能加载模块。

// export-default.js
export default function () {
  console.log('foo')
}
复制代码

上面代码是一个模块文件 export-default.js,它的默认输出是一个函数。其他模块加载该模块时,import 命令可以为该匿名函数指定任意名字。

// import-default.js
import customName from './export-default'
customName() // 'foo'
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享