变量作用域
-
变量作用域的概念:就是一个变量可以使用的范围
-
JS中首先有一个最外层的作用域:称之为全局作用域
-
JS中还可以通过函数创建出一个独立的作用域,其中函数可以嵌套,所以作用域也可以嵌套
var age=18; //age是在全局作用域中声明的变量:全局变量
function f1(){
console.log(name); //可以访问到name变量
var name="周董" //name是f1函数内部声明的变量,所以name变量的作用域就是在f1函数内部
console.log(name); //可以访问到name变量
console.log(age); //age是全局作用域中声明的,所以age也可以访问
}
console.log(age); //也可以访问
//多级作用域
//-->1级作用域
var gender="男";
function fn(){
//问题:
//gender:可以访问
//age: 可以访问
//height:不能访问
//-->2级作用域
return function(){
//问题:
//gender: 通过一级一级作用域的查找,发现gender是全局作用域中声明的变量
//age:
//height:
console.log(gender);
//-->3级作用域
var height=180;
}
var age=5;
}
作用域链
-
由于作用域是相对于变量而言的,而如果存在多级作用域,这个变量又来自于哪里?这个问题就需要好好地探究一下了,我们把这个变量的查找过程称之为变量的作用域链
-
作用域链的意义:查找变量(确定变量来自于哪里,变量是否可以访问)
-
简单来说,作用域链可以用以下几句话来概括:(或者说:确定一个变量来自于哪个作用域)
-
查看当前作用域,如果当前作用域声明了这个变量,就确定结果
-
查找当前作用域的上级作用域,也就是当前函数的上级函数,看看上级函数中有没有声明
-
再查找上级函数的上级函数,直到全局作用域为止
-
如果全局作用域中也没有,我们就认为这个变量未声明(xxx is not defined)
-
-
-
-
-
举例1:
var name="张三";
function f1(){
var name="abc";
console.log(name);
}
f1();
-
举例2:
var name="张三";
function f1(){
console.log(name);
var name="abc";
}
f1();
-
举例3:
var name="张三";
function f1(){
console.log(name);
var name="abc";
}
f1();
-
举例4:
var name="张三";
function f1(){
return function(){
console.log(name);
}
var name="abc";
}
var fn=f1();
fn();
-
举例5:
var name="张三";
function f1(){
return {
say:function(){
console.log(name);
var name="abc";
}
}
}
var fn=f1();
闭包的问题
function fn(){
var a=5;
return function(){
a++;
console.log(a); //a变量肯定是可以访问的
}
}
var f1=fn(); //f1指向匿名函数
f1(); //6
f1(); //7
f1(); //8
//代码执行到20行fn函数执行完毕,返回匿名函数
// -->一般认为函数执行完毕,变量就会释放,但是此时由于js引擎发现匿名函数要使用a变量,所以a变量并不能得到释放,而是把a变量放在匿名函数可以访问到的地方去了
// -->a变量存在于f1函数可以访问到的地方,当然此时a变量只能被f1函数访问
可以看出每次调用a的值+1
下面几个小例子:
//例1:
function fn(){
var a=5;
return function(){
a++;
console.log(a); //a变量肯定是可以访问的
}
}
var f1=fn(); //f1指向匿名函数
f1(); //6
f1(); //7
f1(); //8
//把a变量的值放在f1函数可以访问到的地方
var f2=fn();
f2(); //6
f2(); //7
f2(); //8
//又一次执行了fn,又初始化了一个新的a变量,值为5;返回匿名函数f2,并且把新的a变量放在了f2可以访问到的地方
var f3=fn();
f3(); //6
//又一次执行了fn,又初始化了一个新的a变量,值为5;返回匿名函数f2,并且把新的a变量放在了f2可以访问到的地方
//例2:
function q1(){
var a={};
return a;
}
var r1=q1();
var r2=q1();
console.log(r1==r2);
function q2(){
var a={}
return function(){
return a;
}
}
var t3=q2();//创建一个新的a对象,把a对象放在t3可以访问到的位置
var o5=t3(); //返回值a就是那个a
var w3=q2();//创建了一个新的a对象,把新的a对象放在w3可以访问到的位置
var o8=w3();//此时获取到的是一个新的a对象
console.log(o5==o8); //false
闭包问题的产生原因
-
函数执行完毕后,作用域中保留了最新的a变量的值
闭包的应用场景
-
模块化
-
防止变量被破坏
写了个闭包应用的小案例:var ktv=(function KTV(){//为了保护leastPrice变量,将它放在函数内部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('权限不足');}}}
})()
//有问题:来了一个工商局的朋友要来唱K//——>可能老板需要去修改最低消费的金额//-->但是并不能让老板直接去修改leastPrice,或者说不能把leastPrice作为全局变量
var datepicker=(function(){var hour=3600*1000;return function(){console.log('日期控件初始化');}})();
var common=(function(){return {isStr:function(){
},isNumber:function(){
}}})()最后在我们或许会想到释放闭包内如何操作?function f1(){var a=5;return function(){a++;console.log(a);}}var q1=f1();//要想释放q1里面保存的a,只能通过释放q1q1=null; //q1=undefined