介绍目前常见前端面试题,参考链接 https://interview2.poetries.top/
ES6
ES6 的了解
- 新增模板字符串(为
JavaScript提供了简单的字符串插值功能) - 箭头函数(操作符左边为输入的参数,而右边则是进行的操作以及返回的值
Inputs=>outputs。) for-of(用来遍历数据—例如数组中的值。)arguments对象可被不定参数和默认参数完美代替。ES6将promise对象纳入规范,提供了原生的Promise对象。- 增加了
let和const命令,用来声明变量。 - 增加了块级作用域。
let命令实际上就增加了块级作用域。 - ES6规定,
var命令和function命令声明的全局变量,属于全局对象的属性; let命令、const命令、class命令声明的全局变量,不属于全局对象的属性。- 还有就是引入
module模块的概念
了解ECMAScript6的新特性?
- 块级作用区域
let a = 1; - 可定义常量
const PI = 3.141592654; - 变量解构赋值
var [a, b, c] = [1, 2, 3]; - 字符串的扩展(模板字符串)
var sum =${a + b}; - 数组的扩展(转换数组类型)
Array.from($('li')); - 函数的扩展(扩展运算符)
[1, 2].push(...[3, 4, 5]); - 对象的扩展(同值相等算法)
Object.is(NaN, NaN); - 新增数据类型(Symbol)
let uid = Symbol('uid'); - 新增数据结构(Map)
let set = new Set([1, 2, 2, 3]); - for…of循环
for(let val of arr){}; - Promise对象
var promise = new Promise(func); - Generator函数
function* foo(x){yield x; return x*x;} - 引入Class(类)
class Foo {} - 引入模块体系
export default func; - 引入async函数[ES7]
1 | async function asyncPrint(value, ms) { |
❤ ES6的箭头函数
箭头函数与普通函数的区别?
- 函数体内的
this对象,就是定义时所在的对象,而不是使用时所在的对象 - 不可以当作构造函数,也就是说,不可以使用
new命令,否则会抛出一个错误 - 不可以使用
arguments对象,该对象在函数体内不存在。如果要用,可以用Rest参数代替 - 不可以使用
yield命令,因此箭头函数不能用作Generator函数
得分点 没有this、this是从外部获取、不能使用new、没有arguments、没有原型和super
标准回答 箭头函数相当于匿名函数,简化了函数定义。
- 箭头函数有两种写法,当函数体是单条语句的时候可以省略{}和return。另一种是包含多条语句,不可以省略{}和return。
- 箭头函数最大的特点就是没有this,所以this是从外部获取,就是继承外部的执行上下文中的this,
- 由于没有this关键字所以箭头函数也不能作为构造函数,也就是说,不可以使用
new命令,否则会抛出一个错误 - 同时通过
call()或apply()方法调用一个函数时,只能传递参数(不能绑定this),第一个参数会被忽略。箭头函数也没有原型和super。 - 不能使用yield关键字,因此箭头函数不能用作 Generator 函数。不能返回直接对象字面量。
- 箭头函数有两种写法,当函数体是单条语句的时候可以省略{}和return。另一种是包含多条语句,不可以省略{}和return。
加分回答
箭头函数的不适用场景:
定义对象上的方法 当调用
dog.jumps时,lives并没有递减。因为this没有绑定值,而继承父级作用域。1
2
3
4var dog = {
lives: 20,
jumps: () => { this.lives--; }
}不适合做事件处理程序 此时触发点击事件,this不是button,无法进行class切换
1
2
3
4var button = document.querySelector('button');
button.addEventListener('click', () => {
this.classList.toggle('on');
});
箭头函数函数适用场景:
简单的函数表达式,内部没有this引用,没有递归、事件绑定、解绑定,适用于map、filter等方法中,写法简洁
1
2var arr = [1,2,3];
var newArr = arr.map((num)=>num*num)内层函数表达式,需要调用this,且this应与外层函数一致时
1
2
3
4
5
6
7
8
9let group = {
title: "Our Group",
students: ["John", "Pete", "Alice"],
showList() {
this.students.forEach(
student => alert(this.title + ': ' + student) );
}
};
group.showList();
ES5、ES6和ES2015有什么区别?
ES2015特指在2015年发布的新一代JS语言标准,ES6泛指下一代JS语言标准,包含ES2015、ES2016、ES2017、ES2018等。现阶段在绝大部分场景下,ES2015默认等同ES6。ES5泛指上一代语言标准。ES2015可以理解为ES5和ES6的时间分界线
babel是什么,有什么作用?
babel是一个ES6转码器,可以将ES6代码转为ES5代码,以便兼容那些还没支持ES6的平台
let有什么用,有了 var 为什么还要用let?
在
ES6之前,声明变量只能用var,var方式声明变量其实是很不合理的,准确的说,是因为ES5里面没有块级作用域是很不合理的。没有块级作用域回来带很多难以理解的问题,比如for循环var变量泄露,变量覆盖等问题。let声明的变量拥有自己的块级作用域,且修复了var声明变量带来的变量提升问题。
ECMAScript6 怎么写class么
- 这个语法糖可以让有
OOP基础的人更快上手js,至少是一个官方的实现了 - 但对熟悉
js的人来说,这个东西没啥大影响;一个Object.creat()搞定继承,比class简洁清晰的多
Promise
参考链接
这里你谈
promise的时候,除了将他解决的痛点以及常用的API之外,最好进行拓展把eventloop带进来好好讲一下,microtask(微任务)、macrotask(任务) 的执行顺序,如果看过promise源码,最好可以谈一谈 原生Promise是如何实现的。Promise的关键点在于callback的两个参数,一个是resovle,一个是reject。还有就是Promise的链式调用(Promise.then(),每一个then都是一个责任人)
Promise是ES6新增的语法,解决了回调地狱的问题。- 可以把
Promise看成一个状态机。初始是pending状态,可以通过函数resolve和reject,将状态转变为resolved或者rejected状态,状态一旦改变就不能再次变化。 then函数会返回一个Promise实例,并且该返回值是一个新的实例而不是之前的实例。因为Promise规范规定除了pending状态,其他状态是不可以改变的,如果返回的是一个相同实例的话,多个then调用就失去意义了。 对于then来说,本质上可以把它看成是flatMap
1. Promise 的基本情况
简单来说它就是一个容器,里面保存着某个未来才会结束的事件(通常是异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息
一般 Promise 在执行过程中,必然会处于以下几种状态之一。
- 待定(
pending):初始状态,既没有被完成,也没有被拒绝。 - 已完成(
fulfilled):操作成功完成。 - 已拒绝(
rejected):操作失败。
待定状态的
Promise对象执行的话,最后要么会通过一个值完成,要么会通过一个原因被拒绝。当其中一种情况发生时,我们用Promise的then方法排列起来的相关处理程序就会被调用。因为最后Promise.prototype.then和Promise.prototype.catch方法返回的是一个Promise, 所以它们可以继续被链式调用
关于 Promise 的状态流转情况,有一点值得注意的是,内部状态改变之后不可逆,你需要在编程过程中加以注意。文字描述比较晦涩,我们直接通过一张图就能很清晰地看出 Promise 内部状态流转的情况

从上图可以看出,我们最开始创建一个新的 Promise 返回给 p1 ,然后开始执行,状态是 pending,当执行 resolve之后状态就切换为 fulfilled,执行 reject 之后就变为 rejected 的状态
2. Promise 的静态方法
all方法- 语法:
Promise.all(iterable) - 参数: 一个可迭代对象,如
Array。 - 描述: 此方法对于汇总多个
promise的结果很有用,在 ES6 中可以将多个Promise.all异步请求并行操作,返回结果一般有下面两种情况。- 当所有结果成功返回时按照请求顺序返回成功结果。
- 当其中有一个失败方法时,则进入失败方法
- 语法:
- 我们来看下业务的场景,对于下面这个业务场景页面的加载,将多个请求合并到一起,用 all 来实现可能效果会更好,请看代码片段
1 | // 在一个页面中需要加载获取轮播列表、获取店铺列表、获取分类列表这三个操作,页面需要同时发出请求进行页面渲染,这样用 `Promise.all` 来实现,看起来更清晰、一目了然。 |
allSettled方法Promise.allSettled的语法及参数跟Promise.all类似,其参数接受一个Promise的数组,返回一个新的Promise。唯一的不同在于,执行完之后不会失败,也就是说当Promise.allSettled全部处理完成后,我们可以拿到每个Promise的状态,而不管其是否处理成功
1 | const resolved = Promise.resolve(2); |
从上面代码中可以看到,
Promise.allSettled最后返回的是一个数组,记录传进来的参数中每个 Promise 的返回值,这就是和 all 方法不太一样的地方。
any方法- 语法:
Promise.any(iterable) - 参数:
iterable可迭代的对象,例如Array。 - 描述:
any方法返回一个Promise,只要参数Promise实例有一个变成fulfilled状态,最后any返回的实例就会变成fulfilled状态;如果所有参数Promise实例都变成rejected状态,包装实例就会变成rejected状态。
- 语法:
1 | const resolved = Promise.resolve(2); |
从改造后的代码中可以看出,只要其中一个
Promise变成fulfilled状态,那么any最后就返回这个promise。由于上面resolved这个 Promise 已经是resolve的了,故最后返回结果为2
race方法- 语法:
Promise.race(iterable) - 参数:
iterable可迭代的对象,例如Array。 - 描述:
race方法返回一个Promise,只要参数的Promise之中有一个实例率先改变状态,则race方法的返回状态就跟着改变。那个率先改变的Promise实例的返回值,就传递给race方法的回调函数
- 语法:
- 我们来看一下这个业务场景,对于图片的加载,特别适合用 race 方法来解决,将图片请求和超时判断放到一起,用 race 来实现图片的超时判断。请看代码片段。
1 | //请求某个图片资源 |

promise手写实现,面试够用版:
1 | function myPromise(constructor){ |
详细源码
https://segmentfault.com/a/1190000013396601
对 promise 的了解
- 依照
Promise/A+的定义,Promise有四种状态:pending:初始状态, 非fulfilled或rejected.fulfilled:成功的操作.rejected:失败的操作.settled: Promise已被fulfilled或rejected,且不是pending
- 另外,
fulfilled与rejected一起合称settled Promise对象用来进行延迟(deferred) 和异步(asynchronous) 计算- 可以把
Promise看成一个状态机。初始是pending状态,可以通过函数resolve和reject,将状态转变为resolved或者rejected状态,状态一旦改变就不能再次变化。 then函数会返回一个Promise实例,并且该返回值是一个新的实例而不是之前的实例。因为Promise规范规定除了pending状态,其他状态是不可以改变的,如果返回的是一个相同实例的话,多个then调用就失去意义了
Promise 的构造函数
- 构造一个
Promise,最基本的用法如下:
1 | var promise = new Promise(function(resolve, reject) { |
Promise实例拥有then方法(具有then方法的对象,通常被称为thenable)。它的使用方法如下:
1 | promise.then(onFulfilled, onRejected) |
- 接收两个函数作为参数,一个在
fulfilled的时候被调用,一个在rejected的时候被调用,接收参数就是future,onFulfilled对应resolve,onRejected对应reject
什么是 Promise ?
- Promise 就是一个对象,用来表示并传递异步操作的最终结果
- Promise 最主要的交互方式:将回调函数传入 then 方法来获得最终结果或出错原因
- Promise 代码书写上的表现:以“链式调用”代替回调函数层层嵌套(回调地狱)