参考文档

  • https://juejin.im/post/6844903811622912014#heading-25

    1、ES6新特性

    1.1 ESCMAScript 2015(ES6)有哪些新特性?

    :::success

  • 块作用域

  • 箭头函数
  • 模板字符串
  • 解构赋值
  • 对象结构
  • Promise
  • 模块
  • Symbol
  • 代理(proxy)Set
  • 函数默认参数
  • rest 和展开 :::

    1.2 var、let和const的的区别是什么?

  1. var声明的变量会挂在在window上,相当于全局变量,而let和const声明的变量不会:

    1. var a = 100; console.log(a, window.a); //100 100
    2. let b = 10; console.log(b, window.b); //10 undefined
    3. const c= 1; console.log(c, window.c); //1 undefined
  2. var声明的变量存在变量提升,let和const不存在变量提升:

    1. console.log(a); // undefined ===> a已声明还没赋值,默认得到undefined值
    2. var a = 100;
    3. console.log(b); // 报错:b is not defined ===> 找不到b这个变量
    4. let b = 10;
    5. console.log(c); // 报错:c is not defined ===> 找不到c这个变量
    6. const c = 10;

:::success 在上面的代码中变量a用var声明, 会发生变量提升, 即脚本开始运行时, 变量a已经存在了, 但是没有值, 所以会输出undefined。变量b和c用let和const声明, 不会发生变量提升。这表明在声明之前变量b和c是不存在的, 这时如果用到它,就会抛出一个错误。 :::
3. let和const声明形成块级作用域

  1. if(true){
  2. var a = 100;
  3. let b = 10;
  4. const c = 1;
  5. }
  6. console.log(a);
  7. console.log(b); //b is not defined
  8. console.log(c); //c is not defined
  1. 同一作用域下let和const不能声明同名变量,而var可以:

    1. var a = 100;
    2. console.log(a);
    3. var a = 10 console.log(a);
    4. let a = 1000; //'a' has already been declared
    5. let a = 'aa';
  2. 暂存死区: :::success 只要块级作用域内存在let命令, 它所声明的变量就绑定在这个区域, 不在受外部的影响。 :::

    1. var a = 100;
    2. if(true){
    3. a =10;
    4. let a =1;
    5. }

    :::success 上面的代码中, 存在全局变量a, 但是块级作用域内let又声明了一个局部变量a, 导致后者绑定这个块级作用域, 所以let声明变量前, 对变量a赋值就会报错。
    ES6明确规定, 如果区块中存在let和const命令,这个区块对这些命令的变量, 从一开始就形成了封闭作用域。凡是在声明变量之前使用该变量,就会报错。
    总之,在代码块内, 使用let命令声明变量之前, 改变量都是不可使用的。这在语法上被称为“暂时性死区(TDZ)” :::

  3. const与let区别:

  4. 一旦申明必须赋值,不能使用null占位;
    2. 声明后不能在修改
    3. 如果声明的是引用类型数据,可以修改其属性。

    1. const a = 100;
    2. const list = [];
    3. list[0] = 10;
    4. console.log(list);// [10]
    5. const obj = {a:100};
    6. obj.name = 'apple';
    7. obj.a = 10000;
    8. console.log(obj); // {a:10000,name:'apple'}

    3. 箭头函数是什么?

    JS中 => 是箭头函数,是ES6标准中新增的一种新的函数。箭头函数表达式的语法比函数表达式更简单。并且没有自己的this,argumnets,supernew.target.箭头函数适用于那些本来需要使用匿名函数的地方,并且它不能用作构造函数(箭头函数没有prototype属性)。

    1. const data = {
    2. result: 0,
    3. nums: [1, 2, 3, 4, 5],
    4. computeResult() {
    5. // 这里的“this”指的是“data”对象
    6. const addAll = () => {
    7. return this.nums.reduce((total, cur) => total + cur, 0)
    8. };
    9. this.result = addAll();
    10. console.log(data.result);
    11. }
    12. data.computeResult()

    箭头函数没有自己 的this值。如果在全局作用域声明箭头函数,则this值为window

    4. 什么是Set对象,与WeakSet的区别是什么?

    4.1 Set基本用法: :::success ES6提供了新的数据结构Set.它类似数组,但是成员的值都是唯一的,没有重复的值。
    Set本身是一个构造函数,用来生成Set数据结构。 :::

    1. const s = new Set();
    2. [11,22,33,44,33,22].forEach(x=> s.add(x));
    3. console.log(s); //Set(4) {11, 22, 33, 44}
    4. console.log([...s]); //[11, 22, 33, 44]
    5. console.log(Array.from(s)); //[11, 22, 33, 44]

    Set函数可以接收一个数组(可用于数组去重)

    1. const arr = new Set([00,11,22,33,66,88,33,22,00]);
    2. console.log(arr);
    3. console.log([...arr]);
    4. console.log(arr.size); //6 arr的长度
    5. console.log(arr.delete(11)); //true 是否删除成功
    6. arr.clear()
    7. console.log(arr); //清空数组

    Set 结构的实例有四个遍历方法,可以用于遍历成员:

  • keys()
  • values()
  • entries()
  • forEach()

Set结构转化为数组:

  1. console.log([...s]);
  2. //[11, 22, 33, 44]
  3. console.log(Array.from(s)); //[11, 22, 33, 44]

也可以把Set结构转化为数组类型,可以使用map和filter方法。
Set可以实现并集、交集和差集:

  1. let a = new Set([11,22,33,44]);
  2. let b = new Set([33,66,22,55]);
  3. //并集
  4. let union = new Set([...a,...b]);
  5. //交集
  6. let intersect = new Set([...a].filter(x => b.has(x)));
  7. //差集
  8. let difference = new Set([...a].filter(x => !b.has(x)));

注意:

  1. let s1 = new Set();
  2. s1.add([1]);
  3. s1.add([1]);
  4. console.log(s1.size);
  5. //2
  6. /**
  7. * 这两个数组[1]并不是同一个值,他们分贝定义的数组,在内存中分别对应着不同的存储地址,
  8. * 因此并不是相同的值。所以能存储到Set结构中。
  9. */ let s2 = new Set();
  10. s2.add(1);
  11. s2.add(1);
  12. console.log(s2.size); //1

WeakSet
WeakSet和Set一样也是不重复值的集合。但是和Set的区别:
(1) WeakSet的成员只能是对象,而不能是其他类型

  1. const ws = new WeakSet();
  2. ws.add(1) // TypeError: Invalid value used in weak set ws.add(Symbol())
  3. // TypeError: invalid value used in weak set

(2)WeakSet中的对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用。

  1. const a = [[11,22],[33,44]];
  2. const ws = new WeakSet(a);
  3. console.log(ws);
  4. const b = [11,22];
  5. const ws2 = new WeakSet(b) //报错

WeakSet 结构有以下三个方法:

  • WeakSet.prototype.add(value):向 WeakSet 实例添加一个新成员。
  • WeakSet.prototype.delete(value):清除 WeakSet 实例的指定成员。
  • WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在 WeakSet 实例之中。

    5. 类(class)

    class就是类,和ES5中的构造函数十分类型,但是class的写法能让对象原型的功能更加清晰,更加符合面向对象的语言特点。

    1. class Person{
    2. constructor(name, age)
    3. {
    4. this.name = name;
    5. this.age = age;
    6. this.color = ['red'];
    7. }
    8. getName(){
    9. console.log(this.name);
    10. }
    11. }
    12. class Child extends Person{
    13. constructor(name, age)
    14. {
    15. super(name, age)
    16. }
    17. }
    18. const Jack = new Child('Jack',20);
    19. const Iric = new Child('Iric',23);
    20. Jack.color.push('pink');
    21. Iric.color.push('orange');
    22. Jack.getName();
    23. Iric.getName();
    24. console.log(Jack);
    25. console.log(Iric);

    区别:class的内部所有定义的方法,都是不可枚举的。而原型上面定义的方法都是可以枚举的。
    class所有的方法和属性都定义在类的prototype属性上。

    6. 模块化(Module)

    E6模块不是对象,而是通过export命令显示指定输入的代码,在通过import命令输出。
    模块功能主要由两个命令构成: export和import。

  • export命令用于规定模块的对外接口;

  • import命令用于输入其他模块提供的功能。

    6.1 导出(export)

    ES6允许在一个模块中使用export来导出多个变量来或函数。 ```javascript export let name = ‘lisa’; let name = ‘Jack’; let age = 20; export {name, age}; export function getData(){ //do something }
  1. 通常情况下, export输出的变量就是本来的名字,但是可以使用as关键字重命名。
  2. ```javascript
  3. export { v1 as streamV1, v2 as streamV2, v3 as streamLatestVersion };
  • export和export Default均可以导出常量、函数、文件和模块等;
  • 在一个文件或者模块中,export和import可以有多个,但是export Default只有一个。
  • 通过export导出,在导入的时候需要加{ }, 由export default则不需要加{}.

    6.2 导入(import)

    1. import { firstName, lastName, year } from './profile.js';
    如果想为输入的变量重新取一个名字,import命令要使用as关键字,将输入的变量重命名。
    1. import { lastName as surname } from './profile.js';
    1. import { foo } from 'my_module';
    2. import { bar } from 'my_module';
    3. // 等同于 import { foo, bar } from 'my_module';
    举例:
    1. // circle.js
    2. export function area(radius) {
    3. return Math.PI * radius * radius;
    4. }
    5. export function circumference(radius) {
    6. return 2 * Math.PI * radius;
    7. }
    逐一指定要加载的方法:
    1. // main.js
    2. import { area, circumference } from './circle';
    3. console.log('圆面积:' + area(4));
    4. console.log('圆周长:' + circumference(14));
    整体加载的写法如下:

    7. 函数参数的默认值

    在ES6中,支持定义函数的时候为其设置默认值:
    1. function foo(height = 50, color = 'red') {
    2. // ...
    3. }
    4. 不使用默认值:
    5. function foo(height, color) {
    6. var height = height || 50; var color = color || 'red'; //...
    7. }
    一个容易忽略的地方是,参数默认值不是传值的,而是每次都重新计算默认值表达式的值。也就是说,参数默认值是惰性求值的。

    8. 模板字符串

    ES6支持模板字符串,使得字符串的拼接跟腱简洁、直观。
    1. //不使用模板字符串:
    2. var name = 'Your name is ' + first + ' ' + last + '.'
    3. //使用模板字符串:
    4. var name = `Your name is ${first} ${last}.`

    9. 解构赋值

    9.1 数组的结构赋值

    从数组中获取值并赋值到变量中,变量的顺序与数组中顺序对应。数组的元素是按次序排列的,变量的取值由它的位置决定。
    1. const [a,b,c,d] = [11,22,33,44];
    2. console.log(a,b,c,d); //11 22 33 44
    3. const [a1,b1,c1] = [77,,99];
    4. console.log(a1,b1,c1); //77 undefined 99
    5. //默认值
    6. let [m = 10, n=20] = [null,,];
    7. console.log(m,n); //null 20
    8. let [m = 10, n=20] = [undefined,,];
    9. console.log(m,n); //10 20
    10. //交换2个变量的值
    11. var a = 10;
    12. var b = 20;
    13. [a, b] = [b,a];
    14. console.log(a,b); //20 10

    9.2 对象的解构赋值

    对象的属性没有次序,变量必须与属性名同名,才能取到正确的值。
    1. const student = { name:'Ming', age:'18', city:'Shanghai' };
    2. const {name,age,city} = student;
    3. console.log(name); // "Ming"
    4. console.log(age); // "18"
    5. console.log(city); // "Shanghai"

    10. 延展操作符(spread operator)

    延展操作符…可以在函数调用、数组构造时,将数组或者string在语法层面展开,还可以在构造对象时,将对象表达式按key-value的方式展开。
    函数调用:
    myFunction (…iterableObj)
    数组构造或字符串:
    […iterableObj,’haha’,…’hello’,78]
    对象(浅拷贝):
    let objClone = {…obj}

    11. Promise

    Promise是异步编程的一种解决方案,比传统的解决方案callback更加的优雅。
    Promise构造函数是同步执行的,then()方法是异步执行的。
    不使用promise:
    1. setTimeout(
    2. function() {
    3. console.log('Hello');
    4. // 1秒后输出"Hello"
    5. setTimeout(function() {
    6. console.log('Hi'); // 2秒后输出"Hi"
    7. },
    8. 1000);
    9. }, 1000);
    使用ES6:
    1. var waitSecond = new Promise(function(resolve, reject){
    2. setTimeout(resolve,1000)
    3. });
    4. waitSecond.then(function(){
    5. console.log('hello');
    6. return waitSecond;
    7. }).then(function(){
    8. console.log('nihao');
    9. })
    12. reduce
    1. bookList: [
    2. {
    3. id: 1,
    4. name: "HTML5",
    5. date: "2020-10-23",
    6. price: 25,
    7. count: 10,
    8. },
    9. {
    10. id: 2,
    11. name: "CSS3",
    12. date: "2020-10-23",
    13. price: 25,
    14. count: 10
    15. },
    16. {
    17. id: 3,
    18. name: "React",
    19. date: "2020-10-23",
    20. price: 25,
    21. count: 10,
    22. },
    23. ],
    24. totalPrice() {
    25. let total_price = this.bookList.reduce((prev, cur) => {
    26. return prev + cur.count*cur.price
    27. },
    28. 0);
    29. return total_price;
    30. },
    18 filter
    filter的回调函数有一个要求: 必须返回一个boolean值, 当返回true时,函数内部会自动将这次回调的n加入到新的数组中,返回false,就会过滤掉这个值。

    二、ES7新特性

    2.1 Array.prototype.inlcudes()

    includes() 函数用来判断一个数组是否包含一个指定的值,如果包含则返回true,否则返回false.
    includes函数与indexOf函数相似,下面两个表达式是等价的:
    1. const arr = ['vue','react','CSS3'];
    2. if(arr.indexOf('vue') !== -1){
    3. console.log('vue存在');
    4. }
    5. if(arr.includes('vue')){
    6. console.log('vue存在');
    7. }

    2.2 求幂运算符(**)

    Math.pow(3, 2) === 3 ** 2 // 9

    三、ES8新特性

    3.1 async/await

    答:ES2018引入异步迭代器,这就像常规迭代器,除了next()方法返回一个Promise.因此await可以和for…of循环一起使用,以串行的方式运行异步操作。例如:
    1. async function add(array){
    2. for await (let i of array){
    3. console.log(i);
    4. }
    5. }
    6. add([11,22,33])

    3.2 Object.values()

    Object.values()是一个与Object.keys()类似的新函数,但返回的是Object自身属性的所有值,不包括继承的值。
    1. const obj = {a:11, b:22, c:33};
    2. console.log(Object.keys(obj));
    3. //[ 'a', 'b', 'c' ]
    4. console.log(Object.values(obj)); //[ 11, 22, 33 ]

    3.3 Object.entries()

    Object.entries()函数返回一个给定对象自身可枚举的属性的键值对的数组。
    1. const obj = {a:11, b:22, c:33};
    2. console.log(Object.keys(obj));
    3. //[ 'a', 'b', 'c' ]
    4. console.log(Object.values(obj));
    5. //[ 11, 22, 33 ]
    6. console.log(Object.entries(obj)); [ [ 'a', 11 ], [ 'b', 22 ], [ 'c', 33 ] ]

    3.4 Object.fromEntries()

    将键值对列表转化为一个对象。
    1. const obj = {a:11, b:22, c:33};
    2. console.log(Object.keys(obj));
    3. //[ 'a', 'b', 'c' ]
    4. console.log(Object.values(obj)); //[ 11, 22, 33 ]
    5. console.log(Object.entries(obj));
    6. [ [ 'a', 11 ], [ 'b', 22 ], [ 'c', 33 ] ]
    7. const aa = Object.entries(obj);
    8. console.log(Object.fromEntries(aa)); //{ a: 11, b: 22, c: 33 }

    3.5 Object.getOwnPropertyDescriptors()

    Object.getOwnPropertyDescriptors()函数用来获取一个对象的所有自身属性的描述,如果没有任何属性,则返回空对象。
    1. const obj2 = {
    2. name: 'Jine',
    3. get age() {
    4. return '18'
    5. }
    6. };
    7. console.log(Object.getOwnPropertyDescriptors(obj2));
    四、ES9新特性
    1.Promise.finally()
    一个Promise调用链要么成功到达最后一个.then(),要么失败触发.catch()。在某些情况下,你想要无论失败还是成功都运行一段代码,例如清楚、删除对话框等等。
    .finally()允许你指定最终的逻辑:
    1. function doSomething(){
    2. doSomething1()
    3. .then(doSomething2)
    4. .then(doSomething3)
    5. .catch(err => {
    6. console.log(err);
    7. })
    8. .finally(() => {
    9. //finish here
    10. })
    11. }