变量作用域
- 变量作用域就是指一个变量可以使用的范围。
- JavaScript 中首先有一个最外层的作用域,称之为全局作用域。
- JavaScript 中还可以通过函数创建出一个独立的作用域,其中函数可以嵌套,所以作用域也可以嵌套。
1) 例1
// 全局作用域
var gender = "男";
function fn() {
// 男
console.log(gender);
// undefined:age 变量是在 fn 函数内部声明的,所以能访问,但是此时 age 变量还没被赋值
console.log(age);
// 报错:height 变量不是在 fn 函数内部声明的,所以不能访问
console.log(height);
return function() {
var height = 180;
}
var age = 5;
}
由上可见,JavaScript 中函数执行的时候,首先找到函数内容所有声明的的变量、函数,把他们放在作用域中,并且给变量一个初始值:undefined。接着逐条执行代码,在代码执行过程中,如果有赋值语句,则再对相应的变量赋值。
2)例2
function fn(callback) {
var age = 18;
callback();
}
fn(function() {
// 报错:age is not defined
// 查找 age 变量:
// 1)当前作用域中没有 age 变量
// 2)上一级作用域(全局作用域)中没有 age 变量
console.log(age);
})
总结:查找变量作用域时,并不是看函数在哪里调用,而是看函数在哪里编写
认识闭包
1)例1
function fn() {
var a = 5;
return function() {
a++;
console.log(a);
}
}
// f1 指向了匿名函数
var f1 = fn();
// 6
f1();
// 7
f1();
// 8
f1();
分析:
代码执行到 var f1 = fn(); 时,fn 函数执行完毕,返回匿名函数。一般情况下,函数执行完毕,变量就会释放,但是此时 JavaScript 引擎发现匿名函数要使用 a 变量,所以 a 变量并不能得到释放,而是把 a 变量放到了匿名函数可以访问的地方去了(此时的 a 变量只能被这个匿名函数可以访问到);
2)例2
function fn() {
var a = 5;
return function() {
a++;
console.log(a);
}
}
var f1 = fn();
// 输出 6,执行了 fn 函数,初始化了一个新的 a 变量,值为5;返回匿名函数,并把 a 变量放在了 f1 函数可以访问到的地方
f2();
var f2 = fn();
// 输出 6,又一次执行了 fn 函数,又初始化了一个新的 a 变量,值为5;返回匿名函数,并把新的 a 变量放在了 f2 函数可以访问到的地方
f2();
var f3 = fn();
// 输出 6,又一次执行了 fn 函数,又初始化了一个新的 a 变量,值为5;返回匿名函数,并把新的 a 变量放在了 f3 函数可以访问到的地方
f3();
3)例3
function fn() {
var a = {};
return function() {
return a;
}
}
var f1 = fn();
var f2 = fn();
// false
console.log(f1 == f2);
var g1 = f1();
var g2 = f1();
var g3 = f2();
// true
console.log(g1 == g2);
// false
console.log(g1 == g3);
闭包的自调用
- 无参数
var m = (function() {
})();
以上代码等于:
function module() {
}
var m = module();
- 有参数
var m = (function(global) {
})(window);
以上代码等于:
function module(global) {
}
var m = module(window);
闭包的应用
模块化开发思想:
var k = (function KTV() {
var leastPrice = 1000;
var total = 0;
return {
// 购物
buy:function(price) {
total += price;
}
// 结账
pay:function() {
if (total<leastPrice) {
console.log("请继续购物");
}
else {
console.log("欢迎下次光临");
}
}
// 修改最低消费金额
editLeast:function(id, price) {
if (id == 888) {
leastPrice = price;
console.log("现在最低消费金额为:"+ leastPrice );
}
else {
console.log("权限不足");
}
}
}
})();