闭包是一种特殊的对象。
它由两部分组成。执行上下文(代号A),以及在该执行上下文中创建的函数(代号B)。
当B执行时,如果访问了A中变量对象中的值,那么闭包就会产生。
在大多数理解中,包括许多著名的书籍,文章里都以函数B的名字代指这里生成的闭包。而在chrome中,则以执行上下文A的函数名代指闭包。
因此一个闭包对象,由A、B共同组成,下面以chrome的标准来称呼。
var fn = null;
function foo(){
var a = 2;
function innerFoo(){
console.log(a)
debugger
}
fn = innerFoo; // 将innerFoo 的引用,赋值给全局变量中的 fn
}
function bar () {
fn(); // 此处的保留的 innerFoo 的引用
}
foo();
bar(); // 2
- Closure :为闭包,
- Call Stack :为当前的函数调用栈,
- Scope :为当前正在被执行的函数的作用域链,
- Local :为当前的局部变量。
所以,通过闭包,可以在其他的执行上下文中,访问到函数的内部变量。
在闭包中,能访问到的变量,仍然是作用域链上能够查询到的变量。
对上面的例子稍作修改,如果在函数 bar 中声明一个变量 c,并在闭包 fn 中试图访问该变量,运行结果会抛出错误。
setTimeout(function() {
console.log('一秒后打印')
}, 1000)
每一个 setTimeout 在执行时,会返回一个唯一 ID,上图中的数字 5,就是这个唯一 ID。我们在使用时,常常会使用一个变量将这个唯一 ID 保存起来,用以传入 clearTimeout,清除定时器。
页面中所有由 setTimeout 定义的操作,都将放在同一个队列中依次执行。
队列:先进先出
而这个队列执行的时间,需要等待到函数调用栈清空之后才开始执行。即所有可执行代码执行完毕之后,才会开始执行由 setTimeout 定义的操作。而这些操作进入队列的顺序,则由设定的延迟时间来决定。
for (var i = 1; i <= 5; i++) {
setTimeout(function timer() {
console.log(i);
}, i * 1000);
}
for (var i = 1; i <= 5; i++) {
(function (i) {
setTimeout(function timer() {
console.log(i);
}, i * 1000);
})(i)
}
for (var i = 1; i <= 5; i++) {
setTimeout((function (i) {
return function () {
console.log(i);
}
})(i), i * 1000);
}