JavaScript 的闭包
什么是闭包
-
函数连同它作用域链上的要找的变量,共同构成闭包。
-
闭包就是能够读取其他函数内部变量的函数。
-
「函数」和「函数内部能访问到的变量」(也叫环境)的总和,就是一个闭包。
由于在Javascript语言中,只有函数内部的子函数才能读取其局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。
在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
不必要的闭包只会徒增内存消耗,因此不能滥用闭包,否则会造成网页的性能问题。
在实际操作中,闭包总是和立即执行函数配合使用。 立即实行函数在此是用来隔离作用域的,如果没有它,那这个闭包也毫无意义。
闭包的用途
1. 可以在函数外部读取函数内部声明的变量
function f1() {
var n = 999;
function f2() {
console.log(n);
}
return f2;
}
var result = f1();
result(); // 999
2. 让变量始终保持在内存中
让变量始终保持在内存中,即闭包可以使得它诞生环境一直存在,防止被垃圾回收。闭包使得内部变量记住上一次调用时的运算结果。
function a(n) {
return function () {
return n++;
};
}
let b = a(5);
b() // 5
b() // 6
b() // 7
function add(){
let a =0;
function b(){
a++;
console.log(a);
}
return b;
}
let ab = add();
ab(); //1
ab(); //2
let ab = (function add(){
let a = 0;
function b(){
a++;
console.log(a);
}
return b;
})()
ab(); //1
ab(); //2
3. 利用闭包实现 onclick 事件传递参数。
以下代码会使得点击不同的 li 都返回同一个值,这不是我们想要的结果。
var lis = document.getElementsByTagName('li')
for(var i=0; i<lis.length; i++){
lis[i].onclick=function(){
alert(i)
}
}
以上问题借助闭包可破。
var lis = document.getElementsByTagName('li')
for(var i=0; i<lis.length; i++){
lis[i].onclick=(function(i){
return function(){
alert(i)
}
})(i)
}
或者只是简单地把 var 改为 let,也可以解决问题,虽然不涉及闭包。
let lis = document.getElementsByTagName('li')
for(let i=0; i<lis.length; i++){
lis[i].onclick=function(){
alert(i)
}
}
4. 封装对象的私有属性和私有方法
var Car = (function(){
var speed = 0;
function set(s){
speed = s
}
function get(){
return speed
}
function speedUp(){
speed++
}
function speedDown(){
speed--
}
return {
setSpeed: setSpeed,
get: get,
speedUp: speedUp,
speedDown: speedDown
}
})()
Car.set(30)
Car.get() //30
Car.speedUp()
Car.get() //31
Car.speedDown()
Car.get() //30
function Person(name) {
var age;
function setAge(n) {
age = n;
}
function getAge() {
return age;
}
return {
name: name,
getAge: getAge,
setAge: setAge
};
}
var p1 = Person('张三');
p1.setAge(25);
p1.getAge() // 25
function user(name){
var age, sex;
return{
getName: function(){
return name;
},
setName: function(newName){
name = newName;
},
getAge: function(){
return age;
},
setAge: function(newAge){
age = newAge;
},
getSex: function(){
return sex;
},
setSex: function(newSex){
sex = newSex;
}
}
}
var xm = user('小明')
xm.setSex('男')
xm.setAge(22)
var name = xm.getName()
var sex = xm.getSex()
var age =xm.getAge()
console.log(name, sex, age) //小明 男 22