Skip to main content

2 道前端经典面试题

我太菜了……

第一题

async function async1() {
console.log('ASYNC 1 START')
await async2()
console.log('ASYNC 1 END')
}
async function async2() {
console.log('ASYNC 2')
}
console.log('SCRIPT START')
setTimeout(function () {
console.log('SETTIMEOUT')
}, 0)
async1()
new Promise(function (resolve) {
console.log('PROMISE 1')
resolve()
}).then(function () {
console.log('PROMISE 2')
})
console.log('SCRIPT END')

需要知道的知识点:

  1. JS 是单线程,同步代码在栈中执行,异步代码放入 EventQueue,待栈中的同步代码执行完后,将异步代码从 EventQueue 中取出,放入栈中执行。
  2. EventQueue 中,分微任务队列和宏任务队列,微任务优先级高于宏任务,因此先执行所有微任务,再执行宏任务。
  3. async promise是微任务,setTimeout ajax 事件绑定是宏任务。
  4. 同步代码执行到async await时会创建一个微任务,并直到该微任务执行完毕返回结果后,才继续执行该作用域下的同步代码,但不会阻滞其作用域之外的同步代码执行。
  5. new Promise 会立即把参数中的函数执行,属于同步代码;而 resolve()/reject() 函数属于异步代码,会创建一个微任务。

详细地了解宏任务微任务以及事件队列等机制可跳转:传送门

SCRIPT START
ASYNC 1 START
ASYNC 2
PROMISE 1
SCRIPT END
ASYNC 1 END
PROMISE 2
SETTIMEOUT

第二题

function Foo() {
getName = function () {
console.log(1)
}
return this
}
Foo.getName = function () {
console.log(2)
}
Foo.prototype.getName = function () {
console.log(3)
}
var getName = function () {
console.log(4)
}
function getName() {
console.log(5)
}

Foo.getName()
getName()
Foo().getName()
getName()
new Foo.getName()
new Foo().getName()
new new Foo().getName()

首先

  1. 变量提升:var定义的变量会在代码执行前提升且定义为undefinedfunction定义的函数也会在代码执行前被提升且定义完成,之后不会再次定义。

所以代码执行前,栈中就有FoogetName,且getName是先定义成undefined,后定义成函数

Foo = 地址A
getName = console -> 5

Foo.getName()输出 2

getName()因为代码执行重新赋值,输出 4

Foo().getName()先执行 Foo 函数,将 window 下的 getName 重新赋值,返回 window,输出 1

getName()同上,输出 1

  1. new 操作符:有两种情况,带参数列表(new Foo())和无参数列表(new Foo),这两种情况运算优先级不同。

  2. 运算符优先级

new 操作符 vs 成员访问

因此

new Foo.getName()先进行成员访问,再进行 new 操作,输出 2

new Foo().getName()先执行new Foo(),再执行进行成员访问,new Foo()创建一个实例,实例没有getName方法就去其构造函数的原型对象上找,输出 3

new new Foo().getName()也是先执行new Foo(),执行完后变成new 实例.getName(),此时就变成先访问成员,即构造函数的原型对象的getName方法,再对该方法执行 new 操作,输出 3

Foo.getName() // 2
getName() // 4
Foo().getName() // 1
getName() // 1
new Foo.getName() // 2
new Foo().getName() // 3
new new Foo().getName() // 3