JavaScript 浅谈闭包

在理解闭包是个什么玩意儿之前,我们先来看看JavaScript中的变量作用域,因为闭包和它有着紧密联系。

在JavaScript中,变量根据作用域的不同分为两种:全局变量局部变量

  1. 函数内部可以使用全局变量。

  2. 函数外部不可以使用局部变量。

  3. 当函数执行完毕,本作用域内的局部变量会销毁。

什么是闭包?

在《 JavaScript 高级程序设计 》一书中,给出了闭包的概念:闭包(closure)指有权访问另一个函数作用域中变量的函数

访问另一个函数作用域中的变量的函数,那还不好理解吗,最常用的闭包——就是在一个函数内部创建另一个函数:

 function fn1(){    
    var num = 10;
    function fn2(){
      console.log(num); // 10
    }
       fn2();
 }
  fn1();

不信的话,可以打开chrome浏览器调试闭包:

  1. 打开浏览器,按 F12 键启动 chrome 调试工具。

  2. 设置断点。

  3. 找到 Scope 选项(Scope 作用域的意思)。

  4. 当我们重新刷新页面,会进入断点调试,Scope 里面会有两个参数(global 全局作用域、local 局部作用域)。

  5. 当执行到 fn2() 时,Scope 里面会多一个 Closure 参数 ,这就表明产生了闭包。

闭包的作用?

闭包的主要作用: 延伸了变量的作用范围。

function fn(){
    var num=10;
    return function(){
        console.log(num);
    }
}
var f = fn();//这里相当于f=function(){console.log(num)}
f();//这里即调用了匿名函数

看上面这段代码,我们说当函数执行完毕,本作用域内的局部变量会销毁,但是调用了fn()之后,很明显num还需要在调用 f() 时发挥作用(我还没有被打印,你怎么能说销毁我!!)

闭包的几个小案例

案例1 点击li输出索引号

有这么一个列表:

<ul>
    <li>点我是0</li>
    <li>点我是1</li>
    <li>点我是2</li>
    <li>点我是3</li>
</ul>

要实现点击li输出对应的索引号,聪明人都知道直接这样是行不通的:

window.onload = function(){
	var lis = document.querySelectorAll("li");
	for (var i=0;i<lis.length;i++){
		lis[i].onclick = function(){
			console.log(i);
		}
	}
};

这样的代码最终不管点击哪个li,输出的索引都是4。这和 var 的变量声明有关,如果是ES6中的 let 来声明 i ,那么问题迎刃而解。

但是!任性的我就是想用var来声明呢!?

在以前我们通过给每个li添加自定义的index属性来实现:

window.onload = function(){
	var lis = document.querySelectorAll("li");
	for (var i=0;i<lis.length;i++){
		lis[i].index = i;
		lis[i].onclick = function(){
			console.log(this.index);
		}
	}
};

虽然这种方法也完美实现,但是不知好歹地给人家加了新属性太说不过去。学了闭包之后,我们就可以这么实现:

window.onload = function(){
	var lis = document.querySelectorAll("li");
	for (var i=0;i<lis.length;i++){
		(function(i){
			lis[i].onclick = function(){
				console.log(i);
			}
		})(i);
	}
};

通过立即执行函数(function(){})() 传入参数i,每一次循环都会产生一个立即执行函数。

案例2 定时器中的闭包——3秒之后打印出li的所有内容

代码实现:

window.onload = function(){
	var lis = document.querySelectorAll("li");
	for (var i=0;i<lis.length;i++){
		(function(i){
			setTimeout(function(){
				console.log(lis[i].innerHTML);
			},3000);
		})(i);
	}
};

案例3 计算打车价格

需求:

  1. 打车起步价13元(3公里内), 之后每多一公里增加5块钱.

  2. 用户输入公里数就可以计算打车价格

  3. 如果有拥堵情况,总价格多收取10块钱拥堵费

代码实现:

var carPrice = (function(){
	//起步价
	var start = 13;
	//总价
	var total = 0;
	return {
		price: function(n){
			if (n<=3){
				total = start;
			} else {
				total = (n-3)*5 + start;
			}
			return total;
		},
		yd: function(flag){
			return flag ? total + 10 : total;
		}
	}
})();

console.log(carPrice.price(5));
console.log(carPrice.yd(true));

console.log(carPrice.price(2));
console.log(carPrice.yd(false));

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值