介绍目前常见前端面试题,参考链接 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 代码书写上的表现:以“链式调用”代替回调函数层层嵌套(回调地狱)