回调函数一般作为函数的最后一个参数出现:
function foo1(name, age, callback) { }
function foo2(value, callback1, callback2) { }
回调函数的执行顺序问题:同步->异步->回调;
这里先谈一下回调函数的执行:
var fn = new Function("a","b","return a*b;");
console.log(fn(2, 3));//执行结果为6
js中函数是可以作为参数传递的,
下面我们一代码演示,这应该是最简单的代码演示了:
function fn(arg1, arg2, callback){
var num = arg1+arg2;
console.log("fn函数正在执行");//执行顺序判断
callback(num);
}
fn(10, 20, function(num){
console.log("function函数正在执行");//执行顺序判断
console.log("Callback called! Num: " + num);});
执行结果如下:
一条经典的题目:
for (var i = 1;i < 6;i ++) {
setTimeout(function fn() {
console.log(i)
},i * 1000)
}
这个例子的结构简单描述一下,
for(循环条件){
setTimeOut(函数,间隔时间);//等待间隔时间然后执行函数
}
setTimeOut函数是一个异步队列函数,而for循环是同步,遵循同步执行先于异步执行,那么for循环已经走完了,i的值更新到了5;
我们会发现有五个setTimeOut函数等待执行;
setTimeout(function fn() {
console.log(i) // 异步里面的函数是未执行状态,所以i是现在是不确定的
},1000);
setTimeout(function fn() {
console.log(i)
},2000)
... // 5个待执行函数
这时候1s后,执行第一个setTimeOut函数,此时i要确定值为多少,在函数内找不到i的作用域值,此时需要到外面一层寻找,发现i的值为5,所以之后每次的值都是5,每隔一秒打印一次。
解决这个问题,按我们每隔一秒打印 ,输出结果为1,2,3,4,5,那么可以这样,使用闭包
for (var i = 1;i < 6;i ++) { // 闭包
(function(arg){
setTimeout(function fn() {
console.log(arg)
},arg * 1000)
})(i);//调用时参数
}
在每次循环中,闭包都会执行,两者属于同步关系;
还可以使用es6中let作用域的特点
for (let i = 1;i < 6;i ++) { // es6
setTimeout(function fn() {
console.log(i)
},i * 1000)
}
let作用解释:当用let声明一个变量,它使用的是词法作用域或块作用域。 不同于使用 var声明的变量那样可以在包含它们的函数外访问,块作用域变量在包含它们的块或for循环之外是不能访问的。
当let声明出现在循环体里时拥有完全不同的行为。 不仅是在循环里引入了一个新的变量环境,而是针对 每次迭代都会创建这样一个新作用域。 这就是我们在使用立即执行的函数表达式时做的事,所以在 setTimeout例子里我们仅使用let声明就可以了。