记录下 js 函数的执行时机,困扰了我很久。面试
咱们一个一个例子的来看promise
let a = 1
function fn(){
console.log(a)
}
// 不会打印任何东西,由于函数没有执行
复制代码
let a = 1
function fn(){
console.log(a)
}
fn() // 1
//很简单,一开始声明了 a , a 的值为1,而后调用函数 fn , 打印 a。
复制代码
let a = 1
function fn(){
console.log(a)
}
a = 2
fn() // 2
// 一开始声明了 a , a 的值为1,而后在函数以前将 2 赋值给 a 。 因此打印出 a 的值为2。
复制代码
let a = 1
function fn(){
console.log(a)
}
fn() // 1
a = 2
// 此次是在函数执行后改变 a 的值,函数执行的时候,a 的值依旧为1.
复制代码
经过上面几个例子能够看出,函数中某个变量值的判断,须要肯定函数执行的时机。一开始声明的时候多是某个值,但在函数执行的时候这个值可能已经改变了。bash
再来看几个 异步的例子。闭包
let a = 1
function fn(){
setTimeout(()=>{
console.log(a)
},0)
}
fn() // 2
a = 2
复制代码
这个结果是为2。由于setTimeout
函数会在队列任务执行完后再执行。因此等到打印 a 的时候值已经变为2了。异步
再来看个经典面试题:函数
for(var i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
// 会打印出 六个六。
复制代码
这至关于post
let i
for( i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
复制代码
由于 i 是全局的。for 循环执行完毕以后 i 的值为6。有人奇怪 i 不该该是5吗。i = 5 知足条件(<6)是最后一轮循环,而后i++,i 为6。这个循环自始至终都是在改变一个 i 的值。因此会打印6个6。ui
那我就是想要符合预期的打印0、一、二、三、四、5呢?能够这样:spa
for(let i = 0; i<6; i++){
setTimeout(()=>{
console.log(i)
},0)
}
// 0 1 2 3 4 5
复制代码
这里 let 会单首创建一个做用域 至关于有6个 i 。code
(let i = 0) {
setTimeout(()=>{
console.log(i)
},0)
}
(let i = 1) {
setTimeout(()=>{
console.log(i)
},0)
}
(let i = 2) {
setTimeout(()=>{
console.log(i)
},0)
};
(let i = 3) {
setTimeout(()=>{
console.log(i)
},0)
}
(let i = 4) {
setTimeout(()=>{
console.log(i)
},0)
}
(let i = 5) {
setTimeout(()=>{
console.log(i)
},0)
};
复制代码
咱们还能够这样解决:
for (var i = 0; i < 6; i++) {
setTimeout((function(i){
return function() {
console.log(i);
}
}(i)),0)
}
// 0 1 2 3 4 5
复制代码
最后来看个例子,若是这个知道答案了,那基本上就懂了函数的执行时机:
function f1(){
let a = 1
function f2(){
let a = 2
function f3(){
console.log(a)
}
a = 22
f3()
}
console.log(a)
a = 100
f2()
}
f1()
复制代码
这里有不少 a ,a 有不少值。咱们只须要肯定咱们打印a的时候,a 是哪一个 a 以及 a 是什么值。答案是1和22
。
执行 f1 函数的时候一开始第一个 a 为1,而后有个 f2 函数没执行就先跳过。而后打印 a 。因此咱们能够肯定打印的值为 1 。而后 a = 100 没卵用。
再而后执行 f2 函数。f2 函数中声明了 a = 2 。而后有个 f3 函数没执行就跳过。而后 a = 22。因此以前声明的那个 a 就是22。而后执行 f3 函数。打印 a 为22。就是这么简单,这就是闭包,函数和函数内部可以访问到的函数外的变量。
最后确定还有更加复杂的 setTimeout + promise + nextTick
的执行顺序,涉及了宏任务跟微任务(其实很是简单)
console.log('1');
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
process.nextTick(function() {
console.log('6');
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
复制代码
这里是引用的另一个大佬的啦,有兴趣能够戳这里哦