变量作用域
- JavaScript是函数级作用域编程语言:变量只在其定义时所在的function内部有意义。
全局变量
- 如果不将变量定义在任何函数的内部,此时这个变量就是全局变量,它在任何函数内都可以被访问和更改。
遮蔽效应
- 如果函数中也定义了和全局同名的变量,则函数内的变量会将全局的变量“遮蔽”。
注意考虑变量声明提升的情况
- 这个程序的运行结果是什么呢?
形参也是局部变量
- 这个程序的运行结果是什么呢?
局部函数
- 先来认识函数的嵌套:一个函数内部也可以定义一个函数。和局部变量类似,定义在一个函数内部的函数是局部函数。
作用域链
- 在函数嵌套中,变量会从内到外逐层寻找它的定义。
不加var将定义全局变量
- 在初次给变量赋值时,如果没有加var,则将定义全局变量。
什么是闭包
- JavaScript中函数会产生闭包(closure)。闭包是函数本身和该函数声明时所处的环境状态的组合。
- 函数能够“记忆住”其定义时所处的环境,即使函数不在其定义的环境中被调用,也能访问定义时所处环境的变量。
观察闭包现象
- 在JavaScript中,每次创建函数时都会创建闭包。
- 但是,闭包特性往往需要将函数“换一个地方”执行,才能被观察出来。
闭包非常实用
- 闭包很有用,因为它允许我们将数据与操作该数据的函数关联起来。这与“面向对象编程”有少许相似之处。
- 闭包的功能:记忆性、模拟私有变量。
闭包用途1 - 记忆性
- 当闭包产生时,函数所处环境的状态会始终保持在内存中,不会在外层函数调用后被自动清除。这就是闭包的记忆性。
闭包的记忆性举例
- 创建体温检测函数checkTemp(n),可以检查体温n是否正常,函数会返回布尔值。
- 但是,不同的小区有不同的体温检测标准,比如A小区体温合格线是37.1℃,而B小区体温合格线是37.3℃,应该怎么编程呢?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function createCheckTemp(standardTemp) {
function checkTemp(n) {
if (n <= standardTemp) {
console.log('你的体温正常');
} else {
console.log('你的体温偏高');
}
}
return checkTemp;
}
// 创建一个checkTemp函数,它以37.1度为标准线
var checkTemp_A = createCheckTemp(37.1);
// 再创建一个checkTemp函数,它以37.3度为标准线
var checkTemp_B = createCheckTemp(37.3);
checkTemp_A(37.2);
checkTemp_B(37.2);
</script>
</body>
</html>
闭包用途2 - 模拟私有变量
在Java、C++等语言中,有私有属性的概念,但是JavaScript中只能用闭包来模拟。
- 题目:请定义一个变量a,要求是能保证这个a只能被进行指定操作(如加1、乘2),而不能进行其他操作,应该怎么编程呢?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 封装一个函数,这个函数的功能就是私有化变量
function fun() {
// 定义一个局部变量a
var a = 0;
return {
getA: function () {
return a;
},
add: function () {
a++;
},
pow: function () {
a *= 2;
}
};
}
var obj = fun();
// 如果想在fun函数外面使用变量a,唯一的方法就是调用getA()方法
console.log(obj.getA());
// 想让变量a进行加1操作
obj.add();
obj.add();
obj.add();
console.log(obj.getA());
obj.pow();
console.log(obj.getA());
</script>
</body>
</html>
使用闭包的注意点
- 不能滥用闭包,否则会造成网页的性能问题,严重时可能导致内存泄露。
- 所谓内存泄漏是指程序中己动态分配的内存由于某种原因未释放或无法释放。
立即执行函数IIFE
- IIFE(Immediately Invoked Function Expression,立即调用函数表达式)是一种特殊的JavaScript函数写法,一旦被定义,就立即被调用。
形成IIFE的方法
- 函数不能直接加圆括号被调用。
- 函数必须转为“函数表达式”才能被调用。
IIFE的作用1 - 为变量赋值
- 为变量赋值:当给变量赋值需要一些较为复杂的计算时(如if语句),使用IIFE显得语法更紧凑。
IIFE的作用2-将全局变量变为局部变量
- IIFE可以在一些场合(如for循环中)将全局变量变为局部变量,语法显得紧凑。