概念
闭包(closure)是一个函数以及其捆绑的周边环境状态(词法环境)的引用的组合。换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。闭包会随着函数的创建而被同时创建。
- 创建私有变量
- 已经运行结束的函数上下文中的变量对象继续留在内存中
使用
function makeFunc() {
var name = "Mozilla";
function displayName() {
alert(name);
}
return displayName;
}
// 因为 displayName 创建时作用域里面已经有 name
var myFunc = makeFunc();
myFunc();
用闭包模拟私有方法
返回对象里面的函数引用函数外部的变量
var makeCounter = function () {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function () {
changeBy(1);
},
decrement: function () {
changeBy(-1);
},
value: function () {
return privateCounter;
},
};
};
var Counter1 = makeCounter();
var Counter2 = makeCounter();
console.log(Counter1.value()); /* logs 0 */
Counter1.increment();
Counter1.increment();
console.log(Counter1.value()); /* logs 2 */
Counter1.decrement();
console.log(Counter1.value()); /* logs 1 */
console.log(Counter2.value()); /* logs 0 */
在循环中创建闭包
function showHelp(help) {
document.getElementById("help").innerHTML = help;
}
function setupHelp() {
var helpText = [
{ id: "email", help: "Your e-mail address" },
{ id: "name", help: "Your full name" },
{ id: "age", help: "Your age (you must be over 16)" },
];
// 错误
for (var i = 0; i < helpText.length; i++) {
var item = helpText[i];
document.getElementById(item.id).onfocus = function () {
showHelp(item.help);
};
}
}
setupHelp();
// 闭包
function makeHelpCallback(help) {
return function () {
showHelp(help);
};
}
for (var i = 0; i < helpText.length; i++) {
var item = helpText[i];
document.getElementById(item.id).onfocus = makeHelpCallback(item.help);
}
// 立即执行函数
for (var i = 0; i < helpText.length; i++) {
(function () {
var item = helpText[i];
document.getElementById(item.id).onfocus = function () {
showHelp(item.help);
};
})();
}
// let
for (let i = 0; i < helpText.length; i++) {
const item = helpText[i];
document.getElementById(item.id).onfocus = () => {
showHelp(item.help);
};
}
// forEach
helpText.forEach(function (text) {
document.getElementById(text.id).onfocus = function () {
showHelp(text.help);
};
});
定时器
for (var i = 0; i < 5; i++) {
(function (i) {
setTimeout(function () {
console.log(i);
}, i * 1000);
})(i);
}
方法通常应该关联于对象的原型
定义到对象的构造器中会形成闭包影响性能
function MyObject(name, message) {
this.name = name.toString();
this.message = message.toString();
this.getName = function () {
return this.name;
};
this.getMessage = function () {
return this.message;
};
}