我太菜了……
第一题
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')
需要知道的知识点:
- JS 是单线程,同步代码在栈中执行,异步代码放入 EventQueue,待栈中的同步代码执行完后,将异步代码从 EventQueue 中取出,放入栈中执行。
- EventQueue 中,分微任务队列和宏任务队列,微任务优先级高于宏任务,因此先执行所有微任务,再执行宏任务。
async
promise
是微任务,setTimeout
ajax
事件绑定
是宏任务。- 同步代码执行到
async
await
时会创建一个微任务,并直到该微任务执行完毕返回结果后,才继续执行该作用域下的同步代码,但不会阻滞其作用域之外的同步代码执行。 - 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()
首先
- 变量提升:
var
定义的变量会在代码执行前提升且定义为undefined
;function
定义的函数也会在代码执行前被提升且定义完成,之后不会再次定义。
所以代码执行前,栈中就有Foo
和getName
,且getName
是先定义成undefined
,后定义成函数
Foo = 地址A
getName = console -> 5
Foo.getName()
输出 2
getName()
因为代码执行重新赋值,输出 4
Foo().getName()
先执行 Foo 函数,将 window 下的 getName 重新赋值,返回 window,输出 1
getName()
同上,输出 1
-
new 操 作符:有两种情况,带参数列表(new Foo())和无参数列表(new Foo),这两种情况运算优先级不同。
因此
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