ES6

ES6

1.var、let 、const的区别,var变量提升及函数提升

  • var 声明变量存在变量提升,let 和 const 不存在
  • var会与window相映射(会挂一个属性),而let不与window相映射
  • var 的作用范围是函数作用域,而let、const 的作用范围是块级作用域
  • 同一作用域下 let 和 const 不能重复声明变量,而 var 可以
  • 同一作用域下在 let 和 const 声明前使用会存在暂时性死区,即在let、const声明之前,变量不可以使用
  • const
    • 一旦声明必须赋值,不能使用 null 占位
    • 声明后不能再修改
    • 如果声明的是复合类型数据,可以修改其属性

在js代码执行前引擎会先进行预编译,预编译期间会将变量声明与函数声明提升至其对应作用域的最顶端

变量提升:变量的声明会被提升到当前作用域的最上面,变量的赋值不会提升

函数提升:函数的声明会被提升到当前作用域的最上面,但不会调用函数,函数提升优先级高于变量提升。

2.Promise(什么是Promise?)

Promise :ES6引入的异步编程的新解决方案,语法是一个构造函数 ,用来封装异步操作并可以获取其成功或失败的结果. Promise对象有三种状态:初始化pending 成功fulfilled 失败rejected

  • Promise 就是一个对象,用来表示并传递异步操作的最终结果
  • Promise {: PromiseResult} PromiseState:状态 PromiseResult:返回值
  • Promise 最主要的交互方式:将回调函数传入 then 方法来获得最终结果或出错原因
  • Promise 代码书写上的表现:以“链式调用”代替回调函数层层嵌套(回调地狱)p.then().then()

当我们在构造 Promise 的时候,构造函数内部的代码是立即执行的。Promise构造函数是主线程,而Promise.then是微任务.

new Promise((resolve, reject) => {
  console.log('new Promise');
  resolve('success');
});
console.log('finifsh');

// 先打印new Promise, 再打印 finifsh

调用Promise对象的then方法,两个参数为函数,返回的是promise对象,对象状态由回调函数的执行结果决定 .

	//创建Promis对象
	const p = new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve("成功");
        }, 1000);
      });
  
      //1.如果回调函数中的返回结果是 非promise对象,状态为成功,返回值为对象成功值fulfilled
      const result = p.then(
        (value) => {
          console.log(value); //成功
          return 1;
        },
        (reason) => {}
      );
      console.log(result); //Promise {<fulfilled>: 1}
-------------------------------------------------------------------------------------------
      //2.如果回调函数中的返回结果是promise对象,此promise对象决定上面promise对象p的状态
      const result = p.then(
        (value) => {
          console.log(value); //成功
          return new Promise((resolve, reject) => {
            resolve("ok"); 
            reject("err"); 
          });
        },
        (reason) => {}
      );
      console.log(result);// //Promise {<fulfilled>: 'ok}  Promise {<rejected>: 'err'} 
-------------------------------------------------------------------------------------------
      //3.抛出错误
      const result = p.then(
        (value) => {
          console.log(value); //成功
          throw "出错啦"; 
        },
        (reason) => {}
      );
      console.log(result); // Promise {<rejected>: '出错啦'} 

​ Promise 实现了链式调用,也就是说每次调用 then 之后返回的都是一个 Promise,并且是一个全新的 Promise,原因也是因为状态不可变。如果你在 then 中 使用了 return,那么 return 的值会被 Promise.resolve() 包装。

Promise.resolve(1)
  .then((res) => {
    console.log(res); // => 1
    return 2; // 包装成 Promise.resolve(2)
  })
  .then((res) => {
    console.log(res); // => 2
  });

Promise 也很好地解决了回调地狱的问题.

回调地狱:一个异步请求套着一个异步请求,一个异步请求依赖于另一个的执行结果,使用回调的方式相互嵌套,代码可读性低、编写费劲、不方便后期维护

ajax(url)
  .then((res) => {
    console.log(res);
    return ajax(url1);
  })
  .then((res) => {
    console.log(res);
    return ajax(url2);
  })
  .then((res) => console.log(res));

3.async和await

asyncawait两种语法结合可以让异步代码看起来像同步代码一样,简化异步函数的写法

async函数:

1.async函数的返回值为promise对象;

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

3.async 是Generator函数的语法糖,并对Generator函数进行了改进,是对 yield 的简单封装

    async function fn() {
      //1.如果返回结果是 非promise对象,状态为成功,返回值为对象成功值fulfilled
      return 123;
      //2.抛出错误
      throw "出错啦";
    }
    const result = fn();
    console.log(result); // Promise {<fulfilled>: 123} Promise {<rejected>: '出错啦'}
-----------------------------------------------------------------------------------------
    async function fn() {
      //3.如果返回的promise对象,那么返回的最终结果就是Promise对象
      return new Promise((reslove, reject) => {
        //resolve('成功');
        reject('失败');
      })
    }
    const result = fn();
    console.log(result); //Promise {<rejected>: '失败'}
    // then方法来获得最终结果或出错原因
    result.then(
      (value) => {
        console.log(value);
      },
      (reason) => {
        console.log(reason); //失败
      }
    )

await表达式:

1.await必须写在aysnc函数中;

2.await后面的表达式一般为Promise对象;

3.await返回的是Promise成功的值;

4.await的Promise失败了,就会抛出异常,无法处理promise返回的reject对象,需要通过try…catch捕获处理.

    //async函数 + await表达式:异步函数
    async function fn() {
      //await 返回的promise成功值
      let result = await new Promise((resolve, reject) => {
      resolve('成功')
    });
      console.log(result); //成功
    }
    fn();

一个await 的例子:

let a = 0;
let b = async () => {
  a = a + (await 10);
  console.log('2', a);
};
b();
a++;
console.log('1', a);

//先输出  ‘1’, 1
//在输出  ‘2’, 10
  • 首先函数 b 先执行,在执行到 await 10 之前变量 a 还是 0,因为 await 内部实现了 generator ,generator 会保留堆栈中东西,所以这时候 a = 0 被保存了下来
  • 因为 await 是异步操作,后来的表达式不返回 Promise 的话,就会包装成 Promise.reslove(返回值),然后会去执行函数外的同步代码
  • 同步代码 a++ 与打印 a 执行完毕后开始执行异步代码,将保存下来的值拿出来使用,这时候 a = 0 + 10

上述解释中提到了 await 内部实现了 generator,其实 await 就是 generator 加上 Promise 的语法糖,且内部实现了自动执行 generator

4.箭头函数,以及与普通函数的区别,箭头函数可以当做构造函数 new 吗?箭头函数的作用

箭头函数()=>{}:

  1. 如果形参只有一个,则小括号可以省略;
  2. 函数体如果只有一条语句,则花括号可以省略,函数的返回值为该条语句的执行结果;

与普通函数的区别

  1. 普通函数有函数提升,而箭头函数没有
  2. 箭头函数没有属于自己的thisarguments,箭头函数的this指向为父级:首先从它的父级作用域中找,如果父级作用域还是箭头函数,再往上找,直到找到this的指向。
  3. 箭头函数不能作为构造函数,也就是说,不可以使用new命令(没有this),否则会抛出一个错误。
  4. 没有yield 属性,不能用作生成器 Generator 函数

箭头函数不能new

  • 没有自己的this,不能调用call和apply
  • 没有prototype,new关键字内部需要把新对象的_proto_指向函数的prototype

箭头函数的作用:

1.语法简洁

2.可以隐式返回

//显示返回
const double3 = numbers.map(number => {
    return number * 2;  
})
//隐式返回
//去掉return和花括号括号,把返回内容移到一行,较为简洁;
const double3 = numbers.map(number => number * 2);

3.不绑定this

this实际上是继承自其父级作用域中的this,箭头函数本身的this是不存在的,这样就相当于箭头函数的this是在声明的时候就确定了,this的指向并不会随方法的调用而改变

6.异步实现方式及各自方式的优缺点

方式一:回调函数(callback):将一个函数当做参数传到另一个函数里,当那个函数执行完后,再执行传进去的这个函数,这个过程就叫做回调

回调地狱:回调函数层层嵌套,代码可读性低、不方便后期维护

优点:解决了同步的问题(只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。)

缺点:回调地狱,每个任务只能指定一个回调函数,不能 return.

方式二: Promise

Promise就是为了解决callback的问题而产生的。

Promise 实现了链式调用,也就是说每次 then 后返回的都是一个全新 Promise,如果我们在 then 中 return ,return 的结果会被 Promise.resolve() 包装

优点:解决了回调地狱的问题

缺点:无法取消 Promise ,内部抛出的错误需要通过回调函数来捕获

方式三:生成器Gnenrator

Generator是解决异步编程的一种方案,解决回调地狱

你对生成器Gnenrator的理解?

Generator 函数是一个状态机,封装了多个内部状态。执行 Generator 函数会返回一个遍历器(迭代器)对象,可以依次遍历 Generator 函数内部的每一个状态,但是只有调用next方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield表达式就是暂停标志。

必须调用遍历器对象的next方法,使得指针移向下一个状态。也就是说,每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句,如果没有return语句,就执行到函数结束)为止。yield表达式是暂停执行的标记,而next方法可以恢复执行

方式四:async/await

优点:代码清晰,不用像 Promise 写一大堆 then 链,处理了回调地狱的问题

缺点:await 将异步代码改造成同步代码,如果多个异步操作没有依赖性而使用 await 会导致性能上的降低。

7.解决异步回调地狱的方式

Promise、generator、asynac/await

8.forEach、for in、for of的区别

forEach遍历数组,但不能使用break、continue和return语句

for...in是用来循环带有字符串key的对象的方法。实际是为循环”enumerable“(可枚举)对象而设计的

for...of数组对象都可以遍历,遍历对象需要通过和Object.keys()

for in循环出的是key,for of循环出的是value

可枚举属性是指那些内部 “可枚举” 标志设置为 true 的属性。

对于通过直接的赋值和属性初始化的属性,该标识值默认为即为 true。

Js基本数据类型自带的原型属性不可枚举,通过Object.defineProperty0方法指定enumeralbe为false的属性不可枚举。

9.Set、Map的区别

Set集合:类似于数组,但成员的值都是唯一.数组去重

Map集合:类似于对象,也是键值对的集合,但’键’不限于字符串,各种类型的值(包括对象)也可以当做键.

应用场景Set用于数据重组,Map用于数据储存

Set
1,成员不能重复
2,只有键值没有键名,类似数组
3,可以遍历,方法有add, delete,has

Map:
1,本质上是健值对的集合,类似集合
2,可以遍历,可以跟各种数据格式转换

10.filter、map、reudce高阶函数

filter过滤,filter()使用指定的函数测试所有元素,并创建一个包含所有通过测试的元素的新数组。filter中的回调函数必须返回一个boolean值,当返回true时,函数内部会自动将这次回调的n加入到新的数组中,为false时,会过滤这次n.

map映射,map()方法返回一个新数组,数组中的元素为原始数组元素调用函数处理的后值.

reduce()方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。

11.什么是Proxy?

Proxy可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。

12.模块化

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

一个模块是实现一个特定功能的一组方法

优点:1. 防止命名冲突;2. 代码复用;3. 高维护性;

实现模块化方式

  • AMD
  • CMD
  • CommonJS模块
  • ES6 模块

13.模块加载方案比较:CommonJS模块 与 ES6模块

CommonJS模块,它通过 require 来引入模块,通过 module.exports 定义模块的输出接口。这种模块加载方案是服务器端的解决方案,它是以同步的方式来引入模块的,因为在服务端文件都存储在本地磁盘,所以读取非常快,所以以同步的方式加载没有问题。但如果是在浏览器端,由于模块的加载是使用网络请求,因此使用异步加载的方式更加合适。

ES6模块使用 import 和 export 的形式来导入导出模块。

区别:

  • **CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。**CommonJS 模块输出的是值的拷贝,模块内部的变化就影响不到这个值。ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。

  • **CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。**CommonJS 模块就是对象,即在输入时是先加载整个模块,生成一个对象,然后再从这个对象上面读取方法,这种加载称为“运行时加载”。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。

14.解构赋值

数组解构

let [a, b, c] = [1, 2, 3]   //a=1, b=2, c=3
let [d, [e], f] = [1, [2], 3]    //嵌套数组解构 d=1, e=2, f=3
let [g, ...h] = [1, 2, 3]   //数组拆分 g=1, h=[2, 3]
let [i,,j] = [1, 2, 3]   //不连续解构 i=1, j=3
let [k,l] = [1, 2, 3]   //不完全解构 k=1, l=2

对象解构

let {a, b} = {a: 'aaaa', b: 'bbbb'}      //a='aaaa' b='bbbb'
let obj = {d: 'aaaa', e: {f: 'bbbb'}}
let {d, e:{f}} = obj    //嵌套解构 d='aaaa' f='bbbb'
let g;
(g = {g: 'aaaa'})   //以声明变量解构 g='aaaa'
let [h, i, j, k] = 'nice'    //字符串解构 h='n' i='i' j='c' k='e'
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值