1 闭包的定义
保持了自在变量不被开释的函数, 称为闭包,(自在变量指不在自身高低文,也不在全局高低文中的变量)。
那末闭包函数的特性在那里,我们晓得函数在建立的时刻,它的[[scope]]属性就已肯定并不能够转变,所以闭包函数在建立的时刻就保存了上级的作用域链,闭包函数经由过程作用域链去寻觅运用到的变量,一般情况下,函数在实行终了后,将烧毁函数的实行高低文,然则由于闭包函数的存在,包括闭包函数的上级函数实行终了后,假如闭包函数还存在,那末这个上级函数的作用域中的变量依然保存在内存中供闭包函数接见。
注重:
由定义能够晓得,闭包函数肯定是定义在函数中,才可能有上级的函数作用域能够接见,不然上级作用域就是全局作用域。全局作用域中的变量自身就一直在内存中,所以接见全局作用域中变量的函数不能称为闭包。
var name = 'global';
function func1() {
var name1 = 'func1';
console.log(name);
console.log(name);
function func2() {
console.log(name);
var name2 = 'func2';
function func3() {
console.log(name2);
}
func3();
}
func2();
}
func1();
上面代码中,func3为闭包函数,由于它接见了上级函数作用域中的变量name2,func2不能称为闭包函数,由于它们接见的是全局作用域中的变量name。
2 罕见的闭包场景
2.1 保持变量的闭包
var person = (function(){
var _name = 'yangyiliang';
var _age = 18;
return {
getName: function () {
return _name;
},
getAge: function () {
return _age;
},
addAge: function (num) {
return _age += num;
},
reduceAge: function (num) {
return _age -= num;
}
}
})();
console.log(person.addAge(5)); // 23
console.log(person.reduceAge(3)); //20
上面的代码中,起首外层包裹了一个匿名马上实行函数,制造了一个上级函数作用域,getName和getAge要领都是在其内部,而且接见了上级函数作用域中的变量,所以是闭包,所当匿名函数实行终了后,本该烧毁的实行高低文,却由于闭包函数而保存了作用域中的_name和 _age变量, 经由过程addAge 和reduceAge的效果发明,两个闭包共用保存的作用域。
2.2 保持参数的闭包
function makeSizer(size) {
return function() {
document.body.style.fontSize = size + 'px';
};
}
var size12 = makeSizer(12);
var size14 = makeSizer(14);
var size16 = makeSizer(16);
document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;
上面的代码中,makerSizer函数的返回值即为闭包函数,闭包函数接见上级函数作用域中的参数。
2.3 轮回建立闭包罕见毛病
function bind() {
var arr = document.getElementsByTagName("p");
for(var i = 0; i < arr.length;i++){
arr[i].onclick = function(){
alert(i);
}
}
}
bind();
上面的代码中,假定arr的length为5,想要完成的功用是点击5个P标签离别alert 0,1,2,3,4。然则事实上获得的效果倒是都alert 5。
形成这类效果的缘由就是绑定的多个onclick函数是闭包函数,他们配合运用保存的上级函数作用域中的变量 i 。 for轮回实行完毕后 i 的值即为5。
要想处理这类毛病,就让这些闭包保存差别的上级作用域即可。
function bind() {
var arr = document.getElementsByTagName("p");
for(var i = 0; i < arr.length;i++){
(function (i) {
arr[i].onclick = function(){
alert(i);
}
})(i);
}
}
bind();
或许
function bind() {
var arr = document.getElementsByTagName("p");
for(var i = 0; i < arr.length;i++){
arr[i].onclick = (function(i){
return function () {
alert(i);
}
})(i);
}
}
bind();