闭包定义
一个函数对其周围状态的引用捆绑在一起,这样的组合就是闭包(或者说,函数被引用包围)。闭包可以让你在一个内层函数中可以访问到外层函数的作用域。
function fnOut() {
var name = '张三'
function fnIn() {
alert(name)
}
fnIn()
}
fnOut()
function fnOut() {
var name = '李四'
function fnIn() {
alert(name)
}
return fnIn
}
let myFn = fnOut()
myFn()
function fn1(x) {
return function fn2(y) {
return x + y
}
}
let add2 = fn1(2)
let add4 = fn1(4)
console.log(add2(3)); // =>5
console.log(add4(6)); // =>10
闭包作用
- 解决外部访问不到函数内部变量的问题;
- 局部变量会常驻在内存中;
- 避免使用全局变量,造成全局变量污染。
使用场景
通常当你使用只有一个方法的对象时,可以使用闭包。
闭包实用实例
通过按钮改变 body 字体大小,从而改变使用了相对单位的h1、h2 的字体大小。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
body{
font-size: 16px;
}
h1{
font-size: 1.5em;
}
h2{
font-size: 1.2em;
}
</style>
</head>
<body>
<h1>hello world</h1>
<h2>hi world</h2>
<a href="#" id="fontsize12">12</a>
<a href="#" id="fontsize20">14</a>
<a href="#" id="fontsize24">16</a>
</body>
<script>
// 定义行为
function changeFontSize(size){
return function(){
document.body.style.fontSize = size + 'px'
}
}
// 调用外层函数,给局部变量size赋值
let size12 = changeFontSize(12)
let size20 = changeFontSize(20)
let size24 = changeFontSize(24)
// 添加触发事件
document.getElementById('fontsize12').onclick = size12
document.getElementById('fontsize20').onclick = size20
document.getElementById('fontsize24').onclick = size24
</script>
</html>
使用闭包模拟私有方法
<script>
// 定义一个立即执行函数,让其返回 3 个方法
let Counter = (function(){
// 初始化一个计数器,值为 0
let num = 0
function changeBy(val){
num += val;
}
return {
up:function(){
changeBy(1)
},
down:function(){
changeBy(-1)
},
value:function(){
return num
}
}
})()
console.log(Counter.value()); // => 0
Counter.up()
Counter.up()
console.log(Counter.value()); // => 2
Counter.down()
console.log(Counter.value()); // => 1
</script>
闭包性能考量
闭包在处理速度和内存消耗方面对脚本有负面影响。例如在创建新的对象或类时,方法通常关联到对象原型上,如果方法定义到对象的构造器中,则会导致每次创建新的对象时候,方法会被重新赋一次值。关联到原型上的方法可以被所有创建出来的对象共享。减少内存消耗,提高脚本处理速度。