重新刷jsES5基础知识,看到了闭包这块。遵循着又笨又懒的原则,我不想记录概念,就想知道它是怎么来的,先看个例子(廖雪峰官网闭包中的例子)。
说下想干什么,我想输出的results=[1,4,9]
function count() {
var arr = [];
for (var i=1; i<=3; i++) {
arr.push(function () {
return i * i;
});
}
return arr;
}
var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];
不好意思,js给了我一巴掌,这样输出的结果是16,16,16。出现了问题就要思考 为什么不是1,4,9而是16,16,16呢?我粗鲁的解释下:
1.我想要的运行顺序:
第一步:开始循环跑起来,没毛病。
第二步:变量i来了,给i一个值1,开始计算 1*1=1
第三步:变量i来了,给i一个值2,开始计算 2*2=4
第四步:变量i来了,给i一个值3,开始计算 3*3=9
第五步:循环结束,i=4,我管i现在是啥,我车上的货都弄好了,打包装车[1,4,9]
第六步:拉走
2.实际的运行顺序:
第一步:开始循环跑起来,没毛病。
第二步:变量i来了,开始计算 i*i=i的平方
第三步:变量i来了,开始计算 i*i=i的平方
第四步:变量i来了,,开始计算i*i=i的平方
第五步:循环结束,i=4,我现在车的上的货是[i*i,i*i,i*i],还不能走,重新整理[4*4,4*4,4*4]
第六步:拉走
重点是:我想先给i赋值,循环结束再装箱,实际是把i装箱,循环结束再赋值了。
大家时间都比较紧,所以请大声朗读这样出现错误的原因三遍:被return出来的东西引用会发生变化的变量(例子中的循环变量)。
好的,问题已经出现了,如果我就是需要引用发生变化的变量呢。要解决问题就是闭包这个哥们了。
function count() {
var arr = [];
for (var i=1; i<=3; i++) {
arr.push((function (n) {
return function () {
return n * n;
}
})(i));
}
return arr;
}
var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];
f1(); // 1
f2(); // 4
f3(); // 9
这里面用的到了IIFE(即时执行),请先运用你的大脑记录下他的结构,坐稳了,也就是我们写的那个函数里面的n等于i,原理就是函数的参数n绑定循环变量i,无论i后续如何更改,已绑定到函数参数的值不变; 注意哦是已绑定的参数不变。
(function (window, document, undefined) {
//
})(window, document);
当然只针对我们的例子 其实使用ES6的let声明就解决了。一样输出1,4,9,这里面又能说好多东西呢
function count() {
var arr = [];
for (let i=1; i<=3; i++) {
arr.push(function () {
return i * i;
});
}
return arr;
}
var results = count();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];
时间有限,后续在说些闭包其他的东西,个人觉得闭包的重点就是return返回的东西,例如将函数内的私有变量带出,建议看看廖雪峰官网中关于闭包的解释,还有挺多骚操作的。溜了溜了。
最后 如有错误 欢迎大神指正,不胜感激。