- 普通函数和回调函数有什么区别?
- 什么是闭包?
普通函数和回调函数主要是在调用方式上的区别:
- 普通函数的调用:
调用程序发出对普通函数的调用后,程序立即转向被调用函数的执行,直到被调用函数执行完毕,然后返回调用程序继续执行。
从发出程序的角度来看普通函数的执行过程:调用函数执行 ==> 等待被调用函数执行完毕 ===> 调用函数继续执行。 - 回调函数的调用:
调用程序发出对回调函数的调用后,不等待被调用的回调函数执行,立即返回并继续执行调用程序。
现象:调用程序和被调用函数同时在执行。
当被调用函数执行完毕后,被调用函数调用某个事先准备好的函数来通知调用程序函数执行结束。这个过程就是函数回调。
大部分情况下通俗的说:在其他函数中作为参数使用的函数即为回调函数。
闭包
- 闭包就是指有权访问另一个函数作用域中变量的函数
- 理解闭包的关键:外部函数被调用之后其变量对象本应该被销毁,但是闭包的存在使我们仍然可以访问外部函数的变量对象
- 简单说:函数 A 中有一个函数 B,函数 B 可以访问到函数 A 中的变量,那么函数 B 就是闭包。
示例如下:
function fun1() {
let a = 1
window.fun2 = function() {
console.log(a)
}
}
fun1()
fun2() // 1
在 JS 中闭包存在的意义就是让我们可以间接访问函数内部的变量。
- 经典面试题:循环中使用闭包解决 var 定义变量的问题
for(var i = 1; i <= 5; i++) {
setTimeout(function timer() {
console.log(i)
}, i * 1000)
}
// 结果输出 5 个 6
因为 setTimeout 是一个异步函数,所以会先把循环执行完毕,这时候 i 就是 6 了,所以会输出 5 个 6
解决方案如下: 更多解决方案请戳...
// 1. 闭包 首先使用立即执行函数将 i 传入函数内部,这个时候就会被固定在参数 j 上不会改变,当下次执行 timer 这个闭包的时候,就可以使用外部函数的变量 j
for(var i = 1; i <= 5; i++) {
(function(j) {
setTimeout(function timer() {
console.log(j)
}, j * 1000)
})(i)
}
// 2. 使用 setTimeout 的第三个参数
for(var i = 1; i <= 5; i++) {
setTimeout(function timer(j) {
console.log(j)
}, i * 1000, i)
}
// 3. 使用 let 来定义 i 解决问题
for(let i = 1; i <= 5; i++) {
setTimeout(function timer() {
console.log(i)
}, i * 1000)
}
网友评论