闭包概念:
当内部函数被保存到外部时,将会生成闭包。闭包会导致原有作用域链不释放,造成内存泄漏。
什么时候才会触发闭包呢?
当两个函数互相嵌套,把里面的函数被保存到了外部(全局),里面的函数在外面执行的时候,一定能够调用里面的变量。
看下面这个例子:
a函数里面包含b函数,执行a的时候,返回了b函数,赋值给了外部变量demo,通过作用域及上下文的学习可理解到,因为a和b是引用关系,虽然a执行完后销毁了自己的AO,但是被b保留下来了,并将引用地址保留到了外部的变量。
上面的函数,可以用图解来说明其作用域及执行上下文关系:
a被定义和执行的状态图,如下图
b被定义的状态如下图
a执行完就释放了自己的AO,但是b还引用了a的AO,并保留到了外部(全局),如下图
闭包的作用:
- 实现公有变量 eg:函数累加器
- 可以做缓存(存储结构) eg:eater
- 可以实现封装,属性私有化。eg:Person()
- 模块化开发,防止污染全局变量
看一个例子:
1-为什么返回的函数数组结果是 10 ?
理解核心:返回的是函数数组,数组中的每个元素都形成一个闭包(并共用同一个闭包),所以,当外部执行这个闭包时,预编译里的AO对象,它的 i 因for循环,最后值已经变为了 10。
2-这是不好的闭包例子,因为它输出了10个 10,怎么改成一个好的闭包,让它循环输出对应的0123456789;
//问题1-为什么输出 10 ?
function test() {
var arr = [];
for (var i = 0; i < 10; i ++) {
arr[i] = function () {
document.write(i)
}
}
return arr;
}
//问题2-这是不好的闭包例子,因为它输出了10个 10,怎么改成一个好的闭包,让它循环输出对应的0123456789;
var myArr = test();
for(var j = 0; j < 10; j++){
myArr[j]();
}
------------------------------------------------------------------------------------
//修改后
function test() {
var arr = [];
for (var i = 0; i < 10; i ++) {
//下面是一个立即执行函数,j为形参,接收循环的每一个i,独立保存到了外部
(function (j) {
arr[j] = function () {
document.write(j)
}
}(i))
}
return arr;
}
var myArr = test();
for(var j = 0; j < 10; j++){
myArr[j]();
}
可以实现封装,属性私有化,如下代码
function Deng(name, wife) {
var prepareWife = "xiaozhang";
this.name = name;
this.wife = wife;
this.devorce = function () {
this.wife = prepareWife;
}
this.changePrepareWife = function (target) {
prepareWife = target;
}
this.sayPreparewife = function () {
console.log(prepareWife);
}
}
//创建邓哥这个角色,原配老婆叫xiaoliu
//当创建出来的时候,还带了三个闭包,三对一的闭包:devorce changePrepareWife sayPreparewife
//怎么理解呢?
//这几个闭包是外人看不见的,只有邓哥自己知道,是邓哥的私有数据
var deng = new Deng('deng', 'xiaoliu');
//直接打印deng.prepareWife 是没有这个属性的
//只有他执行了changePrepareWife (改变了预备人选)再sayPreparewife (说出来),才知道他有其它妻子人选