前端面试:闭包

闭包一般是ES5中用来解决函数外变量的问题的。

首先介绍一下变量作用域

// 1. 变量作用域:变量在什么范围内是可用的。
// name 在{}内外都可以使用,对于{}来说它并不是变量的一个限制
{
  var name = 'why';
  console.log(name); 
}
console.log(name);

上面的代码看起来没有什么问题,甚至有人还觉得代码块外还能调用变量是一个很方便的事情。

那么没有块级作用域会引起什么问题呢?

// 2.没有块级作用域引起的问题: if的块级
// func()目的就是为了打印'why',但是func()在外部调用的时候,有可能把name进行修改,就导致func()的输出和预期的不一样
var func;
if(true){
  var name = 'why';
  func = function(){
    console.log(name);
  }
}
name = 'kobe'
func()

再来看看for的块级问题.
需求是点击哪个按钮就输出哪个按钮的下标。但是运行起来后无论点击哪个 输出的i都是5

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<button>按钮1</button>
		<button>按钮2</button>
		<button>按钮3</button>
		<button>按钮4</button>
		<button>按钮5</button>
	</body>
	<script>
    // 2.没有块级作用域引起的问题: for的块级
	var btns =document.getElementsByTagName("button");
	for(var i=0; i<btns.length;i++){
		btns[i].addEventListener('click',function(){ // 方法中的i 引用的一直是外面的变量i 而外部变量i已经被修改成了5
			console.log('第'+ i +'个按钮被点击 ')    // 第5个按钮被点击
		})
	}
	</script>
</html>

那么如何解决呢?就是使用闭包。

// 为什么闭包可以解决问题:因为函数是一个作用域
var btns = document.getElementsByTagName("button");
	for(var i=0; i<btns.length;i++){
    // 这种写法就相当于定义一个匿名函数 然后直接调用
		(function (num){
			btns[i].addEventListener('click',function(){
				console.log('第'+ num +'个按钮被点击 ')  
			})
		})(i)
}
// 写成这种方式可能更容易理解一点
var btns =document.getElementsByTagName("button");
	for(var i=0; i<btns.length;i++){
    function func(num){
      btns[i].addEventListener('click',function(){
				console.log('第'+ num +'个按钮被点击 ')  
			})
    }
	func(i)
}

什么是闭包?
简单来说就是定义一个匿名函数然后立即执行,将需要块级作用域的变量通过参数传入。
再来看一个简单的代码

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<button id='btn'>输出why</button>
	</body>
	<script>
	var btn =document.getElementsById("btn");
	var name = 'why'
	btn.addEventListener('click',function(){
		function func(name){ //定义函数
			console.log(name)  //这个name就不是函数外的name,而是参数name
		}
		func(name) //立即调用
	})
	name = 'kobe'; // 即便这里将name修改了,也不会影响func(name)的输出
	</script>
</html>

写成闭包就是如下

var name = 'why'
(function(name){
	console.log(name)
})(name)

但是写成闭包整个代码结构就很难阅读了
在ES6中加入了let就很方便了,因为使用了let, for{}中就有了块级作用域

const btns = document.getElementsByTagName("button");
for(let i=0; i < btns.length; i++){
  btns[i].addEventListener('click',function(){
		console.log('第'+ i +'个按钮被点击 ');
  })
}

总结

ES5中只有function是作用域

ES5之前因为if和for都没有块级作用域的概念,所以在很多时候,我们都必须借助于function的作用域来解决应用外面变量的问题
ES6中加入了let,let它是有if和for的块级作用域

ES5中的var是没有块级作用域(if/for)
ES6中的let是有块级作用域的(if/for)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值