闭包
闭包是一种实现方式(俺是这样想的),可以是一个可执行函数,js的每个对象其实都是闭包的实现方式。
闭包的特性
- 闭包可以访问外部作用域,即使这个外部作用域已经执行结束。
- 当你定义一个函数时候,实际就是一种闭包的实现方式。只有当这个函数不被其他任何地方调用的时候,闭包就结束了。
- 闭包可以让作用域里的 变量,在函数执行完之后依旧保持没有被垃圾回收处理掉
使用示例
举个栗子:
"use strict";
var myClosure = (function outerFunction() {
var hidden = 1;
return {
inc: function innerFunction() {
return hidden++;
}
};
}());
console.log(myClosure.inc()); // 1
console.log(myClosure.inc()); // 2
console.log(myClosure.inc()); // 3
我们可以看到,当我们运用了外部作用域的变量的时候,闭包并没有结束,而是当不在有调用的时候,才将闭包销毁。
经典面试题
上题!
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(new Date, i);
}, 1000);
}
console.log(new Date, i);
会怎么输出呢?正确答案是:5, 5, 5,5,5,5。
他们之间的输出时间是怎么样的呢?
用箭头表示其前后的两次输出之间有 1 秒的时间间隔,而逗号表示其前后的两次输出之间的时间间隔可以忽略。则结果是这样的:
5 -> 5,5,5,5,5。因为循环过程中,几乎是同时设置了5个定时器。
那么应该怎么修改代码,让期望结果变成:5 -> 0,1,2,3,4。走着:
for (var i = 0; i < 5; i++) {
(function(j) { // j = i
setTimeout(function() {
console.log(new Date, j);
}, 1000);
})(i);
}
console.log(new Date, i);
我们 “创建了一个匿名函数并立刻执行”。达到了期望的效果。那么还有没别的办法呢?我们知道setTimeOut方法第三个参数是可选的。当定时器到期,它们会作为参数传递给function 。所以可以这样写:
for (var i = 0; i < 5; i++) {
setTimeout(function(j) {
console.log(new Date, j);
}, 1000, i);
}
console.log(new Date, i);
或者我们可以将i重新赋值:
var output = function (j) {
setTimeout(function() {
console.log(new Date, j);
}, 1000);
};
for (var i = 0; i < 5; i++) {
output(i);
}
console.log(new Date, i);
或者使用let声明变量i:
for (let i = 0; i < 5; i++) {
setTimeout(function() {
console.log(new Date, i);
}, 1000);
}
// console.log(new Date, i); // 会报错。