变量作用域
变量根据作用域的不同分为两种:全局变量和局部变量。
1. 函数内部可以使用全局变量。
2. 函数外部不可以使用局部变量。
3. 当函数执行完毕,本作用域内的局部变量会销毁
什么是闭包
闭包(closure)指有权访问另一个函数作用域中变量的函数。 ----- JavaScript 高级程序设计
简单理解就是 ,一个作用域可以访问另外一个函数内部的局部变量。
<script>
function fn1(){ // fn1 就是闭包函数
var num = 10;
function fn2(){
console.log(num); // 10
}
fn2()
}
fn1();
</script>
被访问变量的是闭包
在 chrome 中调试闭包
1. 打开浏览器,按 F12 键启动 chrome 调试工具。
2. 设置断点。
3. 找到 Scope 选项(Scope 作用域的意思)。
4. 当我们重新刷新页面,会进入断点调试,Scope 里面会有两个参数(global 全局作用域、local 局部作用域)。
5. 当执行到 fn2() 时,Scope 里面会多一个 Closure 参数 ,这就表明产生了闭包。
闭包的作用
提问:我们怎么能在 fn() 函数外面访问 fn() 中的局部变量 num 呢 ?
<script>
function fn() {
var num = 10;
return function {
console.log(num); // 10
}
}
var f = fn();
f()
</script>
闭包作用:延伸变量的作用范围。
闭包也是高阶函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
// 闭包(closure)指有权访问另一个函数作用域中变量的函数。
// 一个作用域可以访问另外一个函数的局部变量
// 我们fn 外面的作用域可以访问fn 内部的局部变量
// 闭包的主要作用: 延伸了变量的作用范围
function fn() {
var num = 10;
// function fun() {
// console.log(num);
// }
// return fun;
return function() {
console.log(num);
}
}
var f = fn();
f();
// 类似于
// var f = function() {
// console.log(num);
// }
// var f = function fun() {
// console.log(num);
// }
</script>
</body>
</html>
闭包案例
1. 点击小li打印出当前小li的索引号
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
ul li{
cursor: pointer;
}
</style>
</head>
<body>
<ul class="nav">
<li>榴莲</li>
<li>臭豆腐</li>
<li>鲱鱼罐头</li>
<li>大猪蹄子</li>
</ul>
<script>
// 闭包应用-点击li输出当前li的索引号
// 1. 我们可以利用动态添加属性的方式
var lis=document.querySelector('.nav').querySelectorAll('li')
for(var i=0;i<lis.length;i++){
// 下面的点击事件是一个异步任务,而是点击了才执行,前面的是同步任务,会先执行,因此i已经变成了4
lis[i].index=i
lis[i].onclick=function(){
console.log(this.index);
}
}
// 2. 利用闭包的方式得到当前小li 的索引号
for(var i=0;i<lis.length;i++){
// 创建了四个立即执行函数 立即执行函数最后面的()的意思是执行,也可以传入一个参数
// 立即执行函数也成为小闭包因为立即执行函数里面的任何一个函数都可以使用它i的变量
(function(i){
// console.log(i);
lis[i].onclick=function(){
console.log(this.index);
}
})(i);
}
</script>
</body>
</html>
2. 3秒之后打印小li的内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<ul class="nav">
<li>榴莲</li>
<li>臭豆腐</li>
<li>鲱鱼罐头</li>
<li>大猪蹄子</li>
</ul>
<script>
// 闭包应用-3秒钟之后,打印所有li元素的内容
var lis = document.querySelector('.nav').querySelectorAll('li');
for(var i=0;i<lis.length;i++){
// 这个立即执行函数里面的i是用来接收的
(function(i){
setTimeout(function(){
console.log(lis[i].innerHTML);
},3000)
})(i)
}
</script>
</body>
</html>
3. 计算打车价格
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
// 闭包应用-计算打车价格
// 打车起步价13(3公里内), 之后每多一公里增加 5块钱. 用户输入公里数就可以计算打车价格
// 如果有拥堵情况,总价格多收取10块钱拥堵费
// function fn() {};
// fn();
var car=(function(){
var start=13;//起步价
var total=0;//总价
return {
price:function(n){
if(n<=3){
total=start;
}else{
total=start+(n-3)*5
}
return total;
},//正常
yd:function(flag){
return flag ? total+10 :total
}//拥堵
}
})();
console.log(car.price(5));//23
console.log(car.yd(true));//33
console.log(car.price(1));//13
console.log(car.yd(false));//13
</script>
</body>
</html>
因为立即执行函数,所以start和total都是闭包,可以在函数内部传,因此当console.log(car.yd(true));时原先的total还是23,它是在原有的基础上+10;而下面是覆盖操作
闭包总结
1.闭包是什么?
闭包是一个函数 (一个作用域可以访问另外一个函数的局部变量)
2. 闭包的作用是什么?
延伸变量的作用范围