全局变量
变量在函数外定义,即为全局变量:
- 在web页面中全局变量属于 window 对象;
- 全局变量有全局作用域:可应用于页面上的所有脚本;
- 生命周期:全局变量在页面关闭后销毁;
- 变量声明时如果不使用 var 关键字,那么它就是一个全局变量,即便它在函数内定义。
局部变量
变量在函数内声明,即为局部变量:
- 局部变量有局部作用域:只能在函数内部访问;
- 生命周期:局部变量在函数开始执行时创建,函数执行完后局部变量会自动销毁;
- 局部变量和全局变量即便名称相同,它们也是两个不同的变量。修改其中一个,不会影响另一个的值。
函数参数只在函数内起作用,是局部变量。
计数器困境
实例
设想下如果你想统计一些数值,且该计数器在所有函数中都是可用的。你可以使用全局变量,函数设置计数器递增:
var counter = 0;
function add() {
return counter += 1;
}
add();
add();
add(); // 计数器现在为 3
问题
- 页面上的任何脚本都能改变计数器,即便没有调用 add() 函数。
- 如果在函数内部声明计数器,在没有调用函数的情况下将无法修改计数器的值。在 JavaScript 中,所有函数都能访问它们上一层的作用域。JavaScript 支持嵌套函数,嵌套函数可以访问上一层的函数变量:
function add() { var counter = 0; function plus() { return counter += 1; } plus(); }
- 如果我们能在外部访问 plus() 函数,这样就能解决计数器的困境,这时候就需要闭包。
JavaScript 闭包
为什么
- 全局变量:可重用,但易造成全局污染;
- 局部变量:不会造成全局污染 ,但不可重用;
- 闭包:即重用变量,又防止变量被污染。
三步实现
- 用外层函数包裹住受保护的变量和操作变量的内层函数;
- 外层函数将内层函数返回到外部,被外部的变量保存;
- 通过外部变量调用内层函数,访问受保护的变量。
实例
通过函数的自我调用,设置计数器为0,并返回内层函数。
var add = (function () {
var counter = 0;
return function () {
return counter += 1;
}
})();
add();
add();
add(); // 计数器为 3
通过传参创建计数器,及获取内层函数,该参数即为函数的私有变量。
function factory(rate){
// rate 受保护的变量,已经生产的计算器中的rate是不变的
return function(rmb){
return (rmb * rate).toFixed(2);
}
}
// 工厂生产第1个计算器,保存住 rate=0.2639
var rmb1$ = factory(0.2639); // function(rmb){
// return (rmb * 0.2639).toFixed(2);
// }
console.log(rmb1$(1000)); // 263.90
console.log(rmb1$(5000)); // 1319.50
// 工厂生产第2个计算器,保存住 rate=0.1449
var rmb2$ = factory(0.1449); // function(rmb){
// return (rmb * 0.1449).toFixed(2);
// }
console.log(rmb2$(1000)); // 144.90
console.log(rmb2$(5000)); // 724.50
特点
- 函数嵌套;
- 外层函数包含一个受保护的局部变量;
- 外层函数将内层函数对象返回。