theme: fancy
😱前言
已经进入秋招了,作者本人也在着急的准备面试,凭着之前的面试经验,我总结了一份完整的面试题,其中分析了答题思路和答案,还有一些手写题,希望可以帮到所有参加面试的小伙伴!!!
可能有些地方不严谨,写的也比较急,所以希望大家可以评论留言批评指正!!!
写作不易,我已经毫无保留分享自己的毕生所学,那你是不是应该毫不吝啬的给个赞吧!!!
持续更新中,还没有总结完。。。
😊(冲!!!)ES6 篇
😃1. 请你说下为什么ES6中引入了 const,let
回答思路:
- 没有
const、let之前有什么弊端 const、let解决了什么问题
扩展问题:
- let、const 存储方式
开始回答
- 在没有
const、let之前,我们使用var来定义变量,因此我们的作用域只分为两种,也就是全局作用域和块级作用域,因此,我们在使用像for或者if这种关键词时,会有很大的隐患,可能造成变量冲突。
比如说:
-
for: 正常来说,我们在 for 循环中定义其他变量,在结束后 for 中定义的变量应该被销毁,不会修改全局变量,但是由于没有块级作用域的限制,使得本应该销毁的变量没有被销毁。
-
if: 正常我们在
fun函数中会打印x的值1,但是由于var变量提升,并且没有块级作用域的限制,虽然if中的代码不会执行,但是变量 x 会覆盖fun外部的值,导致x打印undefined。var i = 5; for(var i = 3; i < 10; i ++){ // 其他操作 } console.log(i) --------------------------- var x = 1 function fun (){ console.log(x) if(false){ var x = 1 } console.log(x) }
- 在引入
let、const之后,我们引入了新的概念,块级作用域,很好的解决了变量提升和无块级作用域带来的变量冲突的问题。那是如何解决的呢?我们引入新的问题。
扩展回答:
- 在js代码执行之前会经历编译阶段,而在编译阶段会确定当前执行上下文所需要的信息,
变量环境,词法环境,this,作用域链,其中,变量环境用来存放var和function定义的变量,并且初始化值为undefined和地址值,而在执行前变量已经定义好了,也就是所谓的变量提升。而const和let定义的变量存储在词法环境中,在词法环境中维护一个小型栈,按照块的形式,将每一个块级变量压入栈顶,执行后弹出,并且不会初始化,因此在一个块级作用域中提前访问变量会报错,也就是所谓的暂时性死区。
变量查找顺序:先从词法环境中从栈顶到栈底,然后到变量环境中查找,之后沿着作用域链查找。
相关题型:
- 给代码看输出
注意点:
var和function变量提升,并且function优先于var,const 、let块级作用域中的暂时性死区。
😃2. 请你说下Promise?
回答思路:
- 首先回答
Promise是什么? Promise为什么出现,没出现前有什么问题,出现后解决了什么问题?
拓展问题:
Promise执行机制,微任务宏任务Promise的缺陷,async/await语法糖的出现
开始回答:
- 首先,从字面意思来理解,
Promise期约, 是一个用来执行将来要发生的或者即将要发生的事件的对象,它自身有三种状态,pending,fulfilled,rejected,同一时刻只能有一种状态,一旦状态改变,则不能再更改,也不可逆。通过构造函数的方式使用,传入一个执行器回调函数,以此来决定Promise的执行状态。之后通过then方法来决定执行什么样的操作,并且then方法返回一个值会自动包装为Promise从而实现对象的链式调用。(之后可以介绍下其他方法race, all, resolve, reject) - 在
Promise出现之前,我们在书写异步代码时,通过回调的方式来拿到异步返回的值,代码抒写逻辑不连续,除此之外,如果下一次的执行需要依赖上一次的执行结果,会导致代码嵌套,如果嵌套次数太多,就造成了新的问题,回调地狱,使得代码难看难以维护,Promise的出现,通过then方法,解决了函数嵌套的问题,then方法的链式调用,也将回调地狱的问题迎刃而解。
上面回答,只是简单的介绍了下
Promise的用法,没有深入的去讲Promise,有能力的话我们应该扩展去讲它周边的知识
扩展:
1. Promise执行机制
Promise除了解决异步回调的问题之外,还有一个特性,就是它的执行时机,微任务,和微任务对应的还有宏任务,说到这我们不得不讲下浏览器的异步实现机制,为了解决 js 单线程(可能涉及问题:js为什么是单线程?)同步执行的效率问题,我们引入了异步执行机制,而异步执行依赖于 v8引擎 中的消息队列和事件循环机制,也就是js在执行过程中遇到异步任务时,不会立即执行,而是将该事件存放到消息队列当中,而消息队列中存放的任务也就是我们所谓的宏任务,然后继续执行js代码,当所有同步代码执行完毕之后,通过事件循环,也就是一个循环代码for或者while来不停的从消息队列中取出一个事件来执行,这就是异步任务的执行机制。消息队列有一个缺点,就是所有任务都是按顺序执行,因此,如果我们需要执行一些时间粒度小的任务,比如监听DOM的变化去做相应的业务逻辑的时候,再使用消息队列的话会造成严重的效率问题,因为消息队列是先进先出的结构,在该事件添加到消息队列尾部时,消息队列内部可能已经有很多任务了,所以宏任务的执行效率不高,这是就引入了新的概念微任务,在宏任务中包含一个微任务队列,来存放需要执行效率高的事件,在每次宏任务执行完之后,不会着急执行下一个宏任务,而是将该宏任务中的微任务执行完毕,再去执行下一个宏任务。
- js
- 添加微任务:Promise, MutationObserver
- 添加宏任务:script,定时器,I/O,交互事件
- node
- 添加微任务:: nextTick
2. async/await 语法糖
Promise虽然可以链式调用来解决回调地狱,但是还是不够完美,依然是回调的方式书写代码,为了更加符合代码逻辑,推出了async/await语法糖,来用同步的方式书写异步代码。使用 async 修饰的函数代表异步函数,会自动包装返回一个Promise类型的对象,await 关键字用来暂停执行逻辑。通过try/cache来捕获异常,介绍完后,我们来说下它的执行原理。
执行原理:(自执行的生成器 + 协程)
- 生成器(Generator):
yield/*,通过调用*函数来返回一个对象,其中有next,return,trow方法。next 方法用来恢复*函数的执行,yield来暂停*函数的执行。详细使用大家请自己查阅,这里只做大致介绍。 - 协程:协程是一种比线程更加轻量级的存在,可以把协程看成是跑在线程上的任务,一个线程上可以存在多个协程,但是在线程上同时只能执行一个协程,协程不是被操作系统内核所管理,而完全是由程序所控制。这样带来的好处就是性能得到了很大的提升,不会像线程切换那样消耗资源。
通过*函数来创建一个协程,但是该协程不会立刻执行,当调用next方法时,将控制权交给该协程,开始执行,遇到yield关键字后,停止协程,并将控制权返回给父协程,并把 yield 后的值传递给父协程,父协程通过next(value)传值给该子协程。这就是生成器可以实现暂停执行的原理。
Promise 相关手写题:
说明:Promise底层实现了微任务的调用,我们没办法用代码实现,只能通过js模拟执行
Promise 的实现
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MyPromise {
constructor(excutor) {
this.state = PENDING
this.value = null
this.err = null
this.onFulfilledCallback = null
this.onRejectedCallback = null
excutor(this.Resolve, this.Reject)
}
Resolve = val => {
if (this.state == PENDING) {
this.state = FULFILLED
this.value = val
this.onFulfilledCallback && this.onFulfilledCallback(this.value)
}
}
Reject = err => {
if (this.state == PENDING) {
this.state = REJECTED
this.value = err
this.onRejectedCallback && this.onFulfilledCallback(this.err)
}
}
then = (onFulfilled, onRejected) => {
if (this.state == FULFILLED) {
const res = onFulfilled(this.value)
return MyPromise.resolve(res)
}
if (this.state == REJECTED) {
const err = onRejected(this.err)
return MyPromise.reject(err)
}
if (this.state == PENDING) {
this.onFulfilledCallback = onFulfilled
this.onRejectedCallback = onRejected
}
}
static resolve(val) {
return new MyPromise((res, rej) => {
res(val)
})
}
static reject(err) {
return new MyPromise((res

最低0.47元/天 解锁文章
5900

被折叠的 条评论
为什么被折叠?



