《用得上的前端知识》系列 - 你我都很忙,能用100字说清楚,绝不写万字长文
概念
闭包的定义
- 技术/理论角度的定义:闭包是函数和声明该函数的词法环境的组合;
-
- 所有的JavaScript函数都是闭包。 因为函数声明时会设置一个内置属性[[Environment]]来记录当前执行上下文的词法环境。
- 实践角度的定义:闭包就是能够读取其他函数内部变量的函数;
-
- 最简单的闭包就是父函数内返回一个函数,返回函数内引用了父函数内变量;
- 在 chrome 中,闭包的名称是外层函数的函数名。
自由变量:在函数中使用,但却不是函数形参或局部变量的变量。
内存泄漏:是指在计算机科学中,由于疏忽或错误造成程序未能释放已经不再使用的内存的现象。
用途
- 创建私有变量;
- 延长变量的生命周期(让特定变量的值始终保存在内存中)。
注意事项
- 过多的使用 闭包 会导致内存消耗大,在某些浏览器(如 IE)中会产生内存泄漏。
-
- 解决办法:在函数退出前,清空或删除不再使用的变量。
- 闭包允许内层函数引用父函数中的变量,但是该变量是最终值。
- 如果闭包会一直使用,则可以作为全局变量存在;若使用频率不高,尽量让它作为一个局部变量。
闭包经典面试题
// 题目:修改以下代码,使之每隔一秒的时间输出 0 -> 1 -> 2 -> 3 -> 4 -> 5
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(new Date, j);
}, 1000);
}
console.log(new Date, i);
// 参考答案1 -------------------
const tasks = []; // 这里存放异步操作的 Promise
const output = (i) => new Promise((resolve) => {
setTimeout(() => {
console.log(new Date, i);
resolve();
}, 1000 * i);
});
// 生成全部的异步操作
for (var i = 0; i < 5; i++) {
tasks.push(output(i));
}
// 异步操作完成之后,输出最后的 i
Promise.all(tasks).then(() => {
setTimeout(() => {
console.log(new Date, i);
}, 1000);
});
// 参考答案2 -------------------
// 模拟其他语言中的 sleep,实际上可以是任何异步操作
const sleep = (timeountMS) => new Promise((resolve) => {
setTimeout(resolve, timeountMS);
});
(async () => { // 声明即执行的 async 函数表达式
for (var i = 0; i < 5; i++) {
if (i > 0) {
await sleep(1000);
}
console.log(new Date, i);
}
await sleep(1000);
console.log(new Date, i);
})();