闭包
定义: 闭包是指有权访问另一个函数作用域中的变量的函数。
作用:
1)可以在函数的外部访问到函数内部的局部变量。
2)让这些变量始终保存在内存中,不会随着函数的结束而自动销毁。
使用场景:
- 函数作为返回值
- 函数作为参数来传递
**原理:**js基于引用计数的内存管理机制。
引用计数:简单地说,为了保证每块内存都存在引用,也为了保证不存在指向错误的引用,如果指向该内存最后一条引用被移除了,则释放该内存。
闭包例子:
1)作为函数返回值使用
function add() {
var sum = 0;
function operation() {
return sum = sum ? sum + 1 : 1;
}
return operation
}
var a = add();
console.log(a());//1
console.log(a());//2
console.log(a());//3
console.log(a());//4
a = null;
a = add();
console.log(a());//1
a指向add函数的返回值,add函数返回的operation函数包括对sum的引用,所以存放变量sum的内存不会被释放。
2)作为函数参数使用
要求: 创建10个标签,点击的时候输出对应的序号
错误代码:
点击a标签后出现的值全为10;
var i,a
for (i = 0; i < 10; i++) {
a = document.createElement('a')
a.innerHTML = i + '<br />'
a.addEventListener('click',function(e){
e.preventDefault()
console.log(i)
})
document.body.appendChild(a)
}
原因: 在页面加载的一瞬间,for循环已经执行完毕,我再去点标签的时候,i的值已经是10了,所以不管我点第几个标签,打印的都会是10。
正确做法:
使用闭包将变量i的作用范围限制在匿名函数内部,此时i是形参所以不会对for循环里面的i变量参数引用关系。
for (var i = 0; i < 10; i++) {
(function(i){
a = document.createElement('a')
a.innerHTML = i + '<br />'
a.addEventListener('click',function(e){
e.preventDefault()
console.log(i)
})
document.body.appendChild(a)
})(i)
}
闭包封装js的语法:
arg为形参,function()为实参可以为变量,也可以为函数。
(function(arg){
...
...
})(function(){
我们的js库
return {
//模块返回值
}
});