定义
A closure is the combination of a function and the lexical environment
within which that function was declared.
This environment consists of any local variables that were in-scope
at the time the closure was created.
闭包 = 函数 + 环境
环境包含了函数内能访问到的所有局部变量
示例1
function makeFunc() {
var bar = 'bar'
function printBar() {
console.log(bar)
}
// printBar是一个闭包
return printBar
}
let foo = makeFunc()
foo()
// some
// 和上面类似,传递参数
function makeAdder(x) {
return function (y) {
return x + y
}
}
let add2 = makeAdder(2)
add2(5)
// 7
示例2 模拟私有方法
function makeCounter() {
// 私有变量
var privateCounter = 0
// 私有方法
function changeBy(val) {
privateCounter += val
}
return {
increment: function() {
changeBy(1)
},
decrement: function() {
changeBy(-1)
},
value: function() {
return privateCounter
}
}
}
let counter1 = makerCounter()
let counter2 = makerCounter()
counter1.increment()
counter1.increment()
counter1.value() // 2
counter2.value() // 0
示例3
var name = 'window'
var obj1 = {
name: 'my obj',
getNameFunc: function() {
console.log(obj1 === this) // true
return function() {
console.log(global === this) // true
return this.name
}
}
}
obj1.getNameFunc()() // undefined,没有输出'window'
var obj2 = {
name: 'my obj',
getNameFunc: function() {
var that = this
return function() {
return that.name
}
}
}
obj1.getNameFunc()() // 'my obj'
- 全局变量 this global
var a = 1
this.b = 2
global.c = 3
// a不属于this和global
this === global // false
console.log(this.a, this.b, this.c) // undefined, 2, undefined
console.log(global.a, global.b, global.c) // undefined, undefined, 3
示例4 循环中创建闭包的常见错误
- 考虑以下情况(详见参考)
<html>
<body>
<p id="help">Helpful notes will appear here</p>
<p>E-mail: <input type="text" id="email" name="email"></p>
<p>Name: <input type="text" id="name" name="name"></p>
<p>Age: <input type="text" id="age" name="age"></p>
<script>
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();
</script>
</body>
</html>
- node模拟上述情况
function makeFuncs() {
let funcs = []
// var:i的作用域在makeFuncs函数中
for(var i = 0; i < 3; i++) {
funcs.push(() => i)
// funcs.push(function() {return i}) // 等价
}
return funcs
}
let funcs = makeFuncs()
funcs[0]() // 3,不是1
funcs[1]() // 3,不是2
funcs[2]() // 3
- 解决方法
// 方法1,使用工厂函数(factory),返回一个闭包,保留了当时的i
const makeI = function(i) {
return () => i
}
// const makeI = i => () => i // 等价
function makeFuncs() {
let funcs = []
for (var i = 0; i < 3; i++) {
// makeI立即执行,返回一个闭包,保留了当时的i
funcs.push(makeI(i))
}
return funcs
}
// 方法2,在函数表达式中保留当时的i
function makeFuncs() {
let funcs = []
for (var i = 0; i < 3; i++) {
(function () {
var k = i
funcs.push(() => k)
})()
}
return funcs
}
// 方法3,使用let绑定块级作用域
// let:i的作用域在for循环中;var:i的作用域在makeFuncs函数中
function makeFuncs() {
let funcs = []
for(let i = 0; i < 3; i++) {
funcs.push(() => i)
}
return funcs
}
参考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures