[秃破前端面试] —— ES6+ 新特性汇总

前言

年前年后跳槽季,准备从面试内容入手看看前端相关知识点,旨在探究一个系列知识点,能力范围以内的深刻探究一下。重在实践,针对初级前端和准备面试的同窗,争取附上实际的代码例子以及相关试题~系列名字就用【秃破前端面试】—— 由于圈内你们共识,技术与发量成正比。😄但愿你们早日 破瓶颈前端

关于面试题或者某个知识点的文章太多了,这里笔者只是想把我的的总结用代码仓库的形式记录下来并输出文章,毕竟理论不等于实践,知其然也要知其因此然,实践用过才能真正理解~ react

相关系列文章:git

什么是 ES6+ 新特性

说实话,ES6+ 新特性被写成文章已经烂大街了,写得好的有不少,因此若是你看过别人写的很是好的新特性文章,就能够不看这篇,我只是为了完整性就对应着写一下,简单的将各类 API 经过代码使用一下。由于新前端三剑客 HTML5 和 CSS3 都写完了,就不差这一个了。es6

ES6+ 新特性就是指 ES6(也叫 ES2015) 之后更新的全部 JavaScript 标准规范新增的 API。由于 ES6 是一个划时代的更新,而且 ES6 以后每次迭代更新内容都比较少,因此就统称为 ES6+ 了。相对的 ES5 就是本来的 JS 语法,而现今不少框架设计也都是使用 ES6 标准语法进行书写,ES6+ 语法能够经过 babel 编译成 ES5 语法。github

目前,ES6+ 已经更新到最新的 ES10 草案。面试

ES6

ES6 - let/const

这两个关键字对应一个名词,也就是块级做用域。ES5 以前是没有块级做用域这个概念的,而且定义变量也都是经过var来进行声明。var生命的变量是函数级做用域。编程

函数做用域含义:属于这个函数的所有变量均可以在整个函数的范围内使用及复用(在嵌套的做用域中也可使用)。redux

  • ES5 函数做用域
var a = 1;
var b = 1;
function foo () {
    var a = 2;
    console.log('foo:', a, b); // 2, 1
}
console.log('windoiw:', a, b); // 1, 1
复制代码
  • ES6 块级做用域 let
{
    let c = 1;
    let d = 1;
    console.log('scope:', c, d); // 1, 1
  }
  function foo2 () {
    let c = 2;
    let d = 2;
    console.log('foo2:', c, d); // 2, 2
  }
  foo2();
  console.log('window:', c, d); // undefined, undefined
复制代码
  • ES6 块级做用域 const
const aa = 1;
aa = 2; // Uncaught TypeError: Assignment to constant variable.

const bb = {};
bb.a = 1;
console.log(bb);

const cc = [];
cc.push(1);
console.log(cc);

const dd = null;
dd = 1;
console.log(dd); // Uncaught TypeError: Assignment to constant variable.
复制代码

const 的用法与 let 基本一致,只不过 const 定义的是常量,不能被修改。而若是const 定义的是对象或者数组,则仍是能够改的,由于两者属于引用类型,存储的是地址指针,也就是说 const 表明的是变量地址不能被修改。const 定义一个 null 值也是不能被更改的,由于还没被分配内存地址。数组

var 定义的变是函数做用域,没有块的概念,能够跨块访问, 不能跨函数访问。bash

let 定义的变量是块级做用域,只能在块做用域里访问,不能跨块访问,也不能跨函数访问。

const 用来定义常量,使用时必须初始化(即必须赋值),只能在块做用域里访问,并且不能修改。

ES6 - class

常用 React 的同窗应该很是的了解,class 用来声明类组件。而 class 就是 ES6 的语法。而 class 其实也能够换种说法是 ES5 继承的一个语法糖,class 特性可使用 ES5 语法所有实现,只不过 class 更为便捷。

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  say() {
    const sayStr = `Hello, my name is ${this.name}, ${this.age} years old! I'm Person`; console.log(sayStr); } } class Chinese extends Person { constructor(name, age) { super(name, age); this.country = 'Chinese'; } say() { const sayStr = `Hello, my name is ${this.name}, ${this.age} years old! I'm ${this.country} Person`;
    console.log(sayStr);
  }
}

/* ES6 class */
const person = new Person('luffy', 28);
const chinesePerson = new Chinese('周', 33);

person.say();
chinesePerson.say();
复制代码

这里有个注意点就是,若是是子类继承父类,那么子类的constructor内部必须有super(),不然会报错,以下图:

ES6 - 箭头函数

箭头函数,ES6 最有特色的一个特性,让代码看起来简洁了不少,而且也解决了 this 指针的问题。

  • 几种箭头函数的写法
() => console.log(1);
const a = () => 1;
const add = (a, b) => a + b;
const resFunc = (a, b) => () => a + b; // 返回一个函数
复制代码
  • this 指针的指向
var scope = 'window';
var obj = {
scope: 'obj',
funcScope: function() {
  console.log('当前做用域:', this.scope);
},
arrayFuncScope: () => console.log('当前做用域:', this.scope)
}
var obj2 = {
scope: 'obj2'
}
obj.funcScope();                 // obj
obj.arrayFuncScope();            // window
obj.funcScope.call(obj2);        // obj2 
obj.arrayFuncScope.call(obj2);   // window
复制代码

能够看到,箭头函数与建立调用它的代码所在做用域共享一个 this,上面代码箭头函数在调用的时候在第2个和第4个都是在 window 环境下,所以 this 就是 window。

ES6 - 模板字符串

关于模板字符串就是很简单了,以下两段代码就很是的清晰。

/* 字符串 */
  var name = 'luffyZh';
  var es5Str = 'Hello ' + name; 
  const es6Str = `Hello ${name}`;
复制代码

由上面代码可知,ES5 使用符号进行拼接,而 ES6 的模板字符串能够将变量嵌入字符串内,很是方便。

ES6 - 解构赋值以及属性简写

  • 解构赋值

解构赋值也是 ES6 新特性中被使用很是频繁的一个,而且在实际开发过程当中用处很大。

// 对象解构

const obj = { name: 'luffy', email: 'luffy@163.com' };
const { name, email, age } = obj;
console.log(name, email, age); // luffy luffy@163.com undefined
复制代码
// 数组解构
let [a, b, c] = [1, 2, 3];
console.log(a, b, c); // 1, 2, 3

let [aa, bb, cc] = [1, [2 , 3], [4, 5, 6]];
console.log(aa, bb, cc); // 1 [2, 3] [4, 5, 6]
复制代码
// 解构应用 —— 一行代码交换 a b 的值
let a = 1;
let b = 2;
[a, b] = [b, a];
console.log(a, b); // 2, 1
复制代码
  • 属性简写

这个也算是一个小语法糖吧,方便开发的时候快速简洁。

var name = 'luffyzh';
var email = 'luffyzh@163.com';
var person = {
    name,
    email
};
console.log(person); // {name: 'luffyzh', email: 'luffyzh@163.com'}
复制代码

ES6 - 模块化

ES6 为咱们提供了新的模块导入/导出规范。

  • 导入模块 —— import
import React from 'react';
import { useState } from 'react';
import * as Sentry from 'sentry';
复制代码
  • 导出模块 —— export
export const foo = () => 1; // 引入的时候须要带 {}
export default foo = () => 2; // 引入的时候不须要带 {}
复制代码

ES6 - Promise

关于 Promise 的详细介绍,能够去另外一篇文章去查阅~秃破前端面试 —— Promise && Async/Await

ES6 - Generator

ES6 的 Generator 也是一种异步编程解决方案,当初学的时候也是不理解,为啥 ES6 要提供两种异步方案,一个是 Promise 一个是 Generator,不过呢二者确实也都是被应用的十分普遍,各有千秋吧。

Generator 是一个迭代器生成函数,它被调用并不会当即执行,而是返回一个迭代器,而后能够进行异步调用,同时还能够挂起操做,很是的牛X可是使用起来也相对复杂。它有两个特性:

  • function关键字与函数名之间有一个星号
  • 函数体内部使用yield表达式,定义不一样的内部状态。
function* testGenerator() {
    yield 'a';
    yield 'b';
    return 'c';
  }
var g = testGenerator();
复制代码

如上图所示,调用 Generator 函数它返回的是一个迭代器对象,而后经过调用此对象的方法.next()来一步一步执行函数内部的状态,每个 yield 关键字对应着一个状态,而 yield 关键字则是表示在此处暂停执行的意思 (直到使用 next 调用),每一个状态是一个对象有两个属性{value: 此状态的值, done: 迭代器函数是否结束}

  • 应用一: redux-saga

很是流行的 redux 异步处理方案 redux-saga 采用的就是 Generator 实现的。

  • 应用二: antd dva

dva 框架内置处理redux 异步也是使用 Generator 来进行处理的。

ES6 - Set

Set 对象是 ES6 为咱们提供的一个新的数据结构,它是以键值对儿的形式存在,相似于 Map,可是区别在于 Set 对象具备自动去重的功能。

var setObj = new Set([1, 1, 2, 3, 4, 4]);
console.log(setObj); // {1, 2, 3, 4}
setObj.add(1);     // {1, 2, 3, 4}
setObj.add(5);   // {1, 2, 3, 4, 5}
setObj.keys(); // {1, 2, 3, 4, 5}
复制代码
  • 应用:一行代码实现数组去重
var arr = [1, 3, 3, 4, 5];
function uniqueArr(arr) {
    return [...new Set(arr)];
    // return Array.from(new Set(arr));
}
复制代码

从上面能够看出来以下几点:

第一:Set 对象的构造函数能够接收一个数组,而后主动去重。

第二:Set 对象返回的是一个对象,能够经过Array.from方法转换成数组。

ES6 - Symbol

Symbol 是 ES6 新增的一种基础数据类型,ES5 的时候,基础类型只有五种,它们是:NumberStringBooleannullundefined。而 ES6 新增了 Symbol,因此 ES6 的时候,基本数据类型就变成了 6 种。

强调一下,Object 属于复杂类型,并非基础类型。

var a = 1;
var b = '2';
var c = false;
var d = {};
var e = null;
var f = undefined;
var g = Symbol();
console.log(typeof a); // number
console.log(typeof b); // string
console.log(typeof c); // boolean
console.log(typeof d); // object
console.log(typeof e); // object
console.log(typeof f); // undefined
console.log(typeof g); // symbol
复制代码

Symbol 是用来建立惟一性变量的,使用 Symbol 能够为程序建立惟一性的 ID,在建立的时候能够为其新增参数描述该变量,即便参数相同两个 Symbol 也是不一样的。

var s1 = Symbol()
var s2 = Symbol('another symbol')
var s3 = Symbol('another symbol')

s1 === s2 // false
s2 === s3 // false
复制代码

具体来讲它的应用有以下几种:

  • 能够用做对象的 key 值
  • 能够用来定义系统常量
  • 可使用 Symbol 定义类的私有属性/方法

定义私有化方法颇有趣,咱们都知道,ES5 以前 JS 并无私有化方法,类的属性和方法都是能够被访问的,之前也就是经过一些约定来实现,好比_下划线定义的是内部的,外部不要访问,可是也不是不能访问。而经过 symbol 和模块化机制,就能够实现私有化方法,由于类内部属性/方法经过 symbol 声明,在外部是没法新建一个同样的,这就是 symbol 惟一性的应用。

ES6 - 扩展运算符

ES6 扩展运算符能够将数组对象转化成逗号分隔的参数序列,这一样也是很是便捷的 API。

var arr = [1, 2, 3];
console.log(arr);
console.log(...arr);          // 等价于 console.log(1, 2, 3);
复制代码
  • 应用 - 简便的实现数组复制
var arr = [1, 2, 3];
// ES5
var arrCopy = JSON.parse(JSON.stringify(arr));
console.log(arrCopy2 !== arr); // true
// ES6
var arrCopy2 = [...arr];
console.log(arrCopy2 !== arr); // true
复制代码

ES6 - 函数参数默认

function foo(name = 'luffy') {
    console.log(name);
}
foo(); // luffy
复制代码

ES6 - 其余好用便捷的 API

  • Array.prototype.from

    用来将类数组(伪数组对象转换成数组的)。

var objLikeArr = {
   0: 'aaa',
   1: 'bbb',
   2: 'ccc',
   length: 3
 }
 console.log(Array.from(objLikeArr)); // ['aaa', 'bbb', 'ccc']
复制代码

一般咱们接触过的伪数组对象有,arguments、NodeList以及 Set 对象等等,均可以经过此函数进行数组的转化。

  • Array.prototype.isArray

    此函数用来判断对象是不是数组。

// ES5判断
Object.prototype.toString.call([1, 2, 3]);  // "[object Array]"

// ES6 判断
Array.isArray({a: 1, b: 2}); // false
Array.isArray(Array.from([1, 2, 3])); // true
复制代码
  • isNaN
var nan;
isNaN(nan + 1); true
nan + 1 === NaN; false
复制代码

NaN 与 NaN 也不相等。

ES7

ES7 - Array.prototype.includes

includes 函数是 String 和 Array 共有的一个函数,他们都是用来判断子元素是否在一个对象(字符串/数组)内部。

// String

'aaabbbccc'.includes('bbb'); // true
'aaabbbccc'.includes('ddd'); // false
复制代码
// Array

[1, 2, 3, 4].includes(1); // true
[1, 2, 3, 4].includes(5); // false
[1, 2, NaN].indexOf(NaN); // -1
[1, 2, NaN].incldes(NaN); // true
复制代码

能够看到,includes 与以前的 indexOf 的区别有两点:

  • indexOf 返回的是位置,number 类型;includes 返回的是 bool 类型
  • includes 能够判断 NaN 是否在数组里;indexOf 则不能

ES7 - 幂指运算

这里就是一个语法糖。

// ES5 求幂
Math.pow(3, 2); // 9

// ES7 求幂

3 ** 2; // 9
复制代码

ES8

ES8 - Async/Await

关于 Async/Await 的详细介绍,能够去另外一篇文章去查阅~秃破前端面试 —— Promise && Async/Await

ES8 其余特性 API

之因此汇老是由于我的以为除了 Async/Await 算是大块更新外,其余的都是某个小 API 或者语法糖,所以就简单说明一下。

  • Object.values/Object.entries

这个算是一个简化需求吧,以前咱们想获取对象的value值,只能经过以下方法。

var obj = {
    name: 'luffyzh',
    email: 'luffyzh@163.com'
}
// ES5
Object.keys(obj).map((key) => obj[key]);
复制代码

如今,不只能直接获取到 values,还能把 key-value 一块儿返回。

// ES8
Object.values(obj);
Object.entries(obj);
复制代码

  • String Padding

字符串填充,新增了两个有关填充字符串的方法String.prototype.padStartString.prototype.padEnd,容许将空字符串或其余字符串添加到原始字符串的开头或结尾。。

targetLength:当前字符串须要填充到的目标长度。若是这个数值小于当前字符串的长度,则返回当前字符串自己。

padString:(可选)填充字符串。若是字符串太长,使填充后的字符串长度超过了目标长度,则只保留最左侧的部分,其余部分会被截断,此参数的缺省值为 " ",注意,缺省值并非空字符串,而是一个空格字符串。

var str = '0.0';
console.log(str.padStart(4, '10'));
console.log(str.padStart(4));
console.log(str.padEnd(10, 'x'));
console.log(str.padEnd(10));
复制代码

  • Object.getOwnPropertyDescriptors()

用来返回一个对象的全部自身属性/方法的描述符,若是没有任何自身属性,则返回空对象。

var obj = {
    name: 'luffyzh',
    email: 'luffyzh@163.com',
    say() {
      console.log(this.name);
    }
}
Object.getOwnPropertyDescriptors(obj);
复制代码

ES9/ES10

这两个放在一块儿来讲是由于比较新,并且实际用到的我的感受不是特别多,就把我的以为可能会用到的列出来了。

ES9 - Rest/Spread 对象扩展运算

ES6 出现了扩展运算符,可是只是给数组准备的,而扩展运算符很是好用,ES9 所以就扩展到了对象,如今对象也可使用扩展运算来进行便捷操做。

var obj = {
    name: 'aaa',
    email: 'luffyzh@163.com'
}
var obj2 = {...obj};
console.log(obj2);
console.log(obj2 !== obj);
var obj3 = { age: 20, ...obj2 };
复制代码

ES9 - Promise.finally

关于 Promise 的详细介绍,能够去另外一篇文章去查阅~秃破前端面试 —— Promise && Async/Await

ES10 - String.prototype.matchAll

这个 API 我的感受出现的有些晚了,由于匹配全部是一个很常见的需求,可是原来只能匹配第一个。

var str = '11223344113311';
console.log(str.match('11')); // 返回一个数组
console.log(str.matchAll('11')); // 返回一个迭代器

复制代码

能够看到,matchAll 是经过 Generator 来实现的。

ES10 - String的 trimStart()方法和 trimEnd()方法

这两个方法就很简单明了了,就是去除字符串前面和后面的空格。很是简单,就不作介绍了。

ES10 - 新增基础类型 BigInt

因此如今基础类型就变成了:String、Number、Boolean、Null、Undefined、Symbol、BigInt 七种了。

ES5 - 五种 ES6 - 新增 Symbol,六种 ES10 - 新增 BigInt,七种

var bi = BigInt(1111111111);
console.log(bi);
console.log(typeof bi);
复制代码

bigint 在控制台会呈现绿色,number 则是蓝色,而且 bigint 后面会携带一额字符 n。若是不初始化还会报错,从报错能够看出 bigint 会在内部有一个转换。

总结

至此,ES6+ 新特性基本上也就写完了,很粗浅,由于是全部特性的简单介绍,因此当面试官面试的时候,你能够回答上来基本用法就能够了。不过每个特性都是值得深刻研究的,感兴趣的能够去查阅官方文档以及源码实现,这样可以加理解。

相关代码地址:秃破前端面试系列代码

相关文章
相关标签/搜索