闭包:当内部函数被保存到外部时,将生成闭包;闭包会导致原有的作用域链不释放,造成内存泄漏;
如下两个例子:
function test(){
var tmp = 100;
function a(){
console.log(tmp);
}
return a;//把里面的函数保存到了外面
}
var demo = test();
demo();//里面的函数在外面调用
也可以不用return,直接赋给全局变量:
var demo;
function test(){
var tmp = 100;
function a(){
console.log(tmp);
}
demo = a;//把里面的函数保存到了外面
}
test();
demo();//里面的函数在外面调用
简单应用:累加器
一般累加器,可以用全局变量做,每调用一次,count 加1;
var count = 0;
function test(){
count++;
console.log(count);
}
test();
test();
但是累加是独立的功能,不应该依赖全局变量(外部)来做,利用闭包的机制就可以实现
function add(){
var num = 0;
function a(){
console.log(++num);
}
return a;
}
var myAdd = add();
myAdd();
myAdd();
函数每次执行,都不依赖外部变量,可以实现模块化,而且每次都能加1,因为add 的 AO 对象没有销毁,一直存在;
循环打印问题
为了实现打印 0~9,保存了10个function,写了如下代码:
function test(){
var arr = [];
for(var i = 0; i<10; i++){
arr[i] = function(){
console.log(i);
}
}
return arr;
}
var myArr = test();
for(var j = 0; j<myArr.length; j++){
myArr[j]();
}
但是运行结果会发现,打印出是 10 个 10;
原因:这里 arr 在保存的时候,是保存 function,里面的内容还没有执行,所以 function 里面不管写什么,arr[i] 在被赋值的时候都是不知道的,必须等到 myArr[j]() 的时候,此时变量 i 存储在 AO 对象中,i 已经累加到了 10,所以
myArr[j] = function(){console.log(10)};
打印 10 个 10;那么如何打印 0 - 9 呢?这里需要引入立即执行函数
立即执行函数
如下:
(function(){
console.log('a');
var tmp = 200;
}())
这种写法会立即执行,执行完后会销毁,无法继续调用;
某些函数只执行一次,不想再调用,比如函数计算求值等;
写法和注意的问题
写法 ( function(){} () ),可传参,在括号中加入即可;
最后一个括号是执行函数的意思;如果写成 function(){} () 不加括号的时候,浏览器会默认为函数定义 function(){} 加上(),所以还需要加一个括号把所有的括起来。
例如:
//立即函数写法,立即执行打印出3
(function test(a,b){
console.log(a+b);
}(1,2))
//错误写法,可执行,但是变成函数定义+无意义语句(1,2)
function test(a,b){
console.log(a+b);
}(1,2)
函数表达式写法也可以
var num = (function (a,b){
return a+b;
}(3,2))
console.log(num);
循环打印实现
利用立即执行函数实现,代码如下:
function test(){
var arr = [];
for(var i = 0; i<10; i++){
(function (j){
arr[j] = function(){
console.log(j);
}
}(i))
}
return arr;
}
var myArr = test();
for(var j = 0; j<myArr.length; j++){
myArr[j]();
}
这里实际上相当于生成了10个立即执行函数,即 arr[0] = function(),arr[1] = function(),arr[2] = function()...,而且同时存了10个j,分别是0,1,...,9,其中 j 存在了每个函数的 AO 对象里;所以 myArr 调用的时候,把 j 拿出后, 放入 function 即可;