一、伪理论:
闭包是什么?
闭包就是利用作用域特性,内部函数可以读取上级函数内的变量,或者说可以读取它创建时的上下文的环境!
闭包有什么用?
可以读取外部函数的参数变量,局部变量,arguments和this除外,原理是外部函数执行后,返回的内部函数一直依赖于外部函数。外部函数的变量没有消逝,可以一直使用。
二、demo片段:
2.1 基本的闭包
function f1(step) {
var a = 999;
return function(){
return a+=step;
}
}
var x = f1(2); //2作为实参,在f1()函数调用完后,一直存在。
console.log(x()); //1001
console.log(x()); //1003 //因为f1调用完,内部变量和step一直不会消失,会被返回的函数x所共享。
2.2 js语言精粹里的渐变例子
var fade = function(node) {
var level = 1;
var step = function() {
var hex = level.toString(16);
node.style.backgroundColor = "#FFFF"+hex+hex; // #FFFF11 (黄色) -> #FFFFFF (白色)
if(level<15){
level+=1;
setTimeout(step, 200); //延时调用并且递归调用自己
}
}
setTimeout(step, 200); //启动延时调用。
}
window.onload = function(){
fade(document.body);
}
//解释: 这个例子和第一个例子不一样,不是调用方法返回一个函数使用,而是调用方法后,持续的延时递归。
//本质其实是一样的,setTimeout()是函数执行完才执行的。等于持续执行step方法改变level的变量。
2.3 for循环的一个问题研究
<script type="text/javascript">
var clickIndex1 = function (nodes) {
for (var i = 0; i < nodes.length; i++) {
//nodes[i].data_index = i;
nodes[i].onclick = function(){
console.log(i);
//console.log(nodes[i].data_index);
}
}
}
//因为for循环的i,执行完后是nodes的长度(最后次遍历length-1,但是会在i++,然后不符合就不执行)
//所以,在内部函数执行的时候,得到外部变量的i一直是长度。
//解决办法1: 去掉注释,采用自定义属性的方式。
//解决办法2: 请看下面
var clickIndex2 = function (nodes) {
for (var i = 0; i < nodes.length; i++) {
nodes[i].onclick = function(j){ /**访问的是j,j是i传递的,而i赋值时是遍历当层进行赋值的。*/
return function(){
console.log(j);
}
}(i);
}
}
window.onload = function () {
var lis = document.querySelectorAll("li");
//clickIndex1(lis); //2,2
clickIndex2(lis); //0,1
}
</script>
<body>
<ul>
<li>111</li>
<li>222</li>
</ul>
</body>
</html>
三、结论:
闭包就是利用函数作用域访问的规则的函数。究其根本就是利用js的函数域是根据函数定义的位置往上延伸。