一.作用域
1. 函数能封闭住定义域
一个变量如果定义在了一个function里面,那么这个变量就是一个局部变量,只在这个function里面有定义,出了这个function,就如同没有定义过一样
function fn(){
var a = 3;//定义在函数里的变量,那么这个变量 就是局部变量,只有在函数里面有定义
console.log("我是函数里面的语句,所以我知道a值是'' + a ");
}
fn();
console.log("我是函数外面的语句,我认为a的值是'' + a"); //undefined

a被var在了function里面,所以现在这个a变量只在函数内定义
JavaScript变量作用域非常的简单,没有块级作用域,管理住作用域的只有一个东西,函数
如果一个变量,没有定义在任何的function中,那么它将在全部程序范围内都有定义:就是你在JS的任何位置都能够使用它。
var a = 10;//定义在全局范围内的一个变量,全局变量,在程序任何一个区域都有定义
function fn(){
console.log("我是函数里面的语句,我认识全局变量a ,它的值为'' + a");
}
fn();
console.log("函数外面的语句,我也认识a,它的值为'' + a");

总结:
- 定义在function里面的变量,叫做局部变量,只在function里面有定义,出了function没有定义的
- 定义在全局范围的 ,没写在任何function里面的,叫做全局变量,全局都认识
2.作用域链
当遇见一个变量时,JS引擎会从其所在的作用域依此向外层 查找,查找会在找到第一个匹配的标识符的时候停止
function outer(){
var a = 3; //a的作用域就是outer
function inner(){
var b = 5; //b的作用域就是inner
console.log(a); //能够正常输出3,a在本层没有定义,就是找上层
console.log(b); //能够正常输出5
}
inner();
}
outer();
console.log(a); //报错,因为a的作用域outer
多层嵌套,如果有同名的变量,那么就会发生”遮蔽效应“
var a =2;//全局变量
function fn(){
var a = 3;//就把外层的a给遮蔽了,这个函数内部看不见外层的a了,
console.log(a);//输出3,变量在当前作用域寻找,找到a的定义为3
}
fn();
console.log(a);//输出为2, 变量在当前作用域寻找,找到a的定义值为2
作用域链:一个变量在使用的时候,就会在当前层寻找它是否被定义,如果找不到,就去找上一层function,知道找到全局变量,如果全局页面没有,就报错。
var a = 1;//全局变量
var b = 2; //全局变量
function outer(){
var a = 3; //遮蔽了外层a,a局部变量
function inner(){
var b = 4;//遮蔽了外层的b,b局部变量
console.log(a);//① 输出3,a现在在当前层找不到定义,所以就上一层寻找
console.log(b); //② 输出4
}
inner(); //调用函数
console.log(a); //③ 输出3
console.log(b); //④ 输出2 b现在在当前层找不到定义就上一层寻找
}
outer(); //执行函数,控制权交给了outer
console.log(a); //⑤ 输出1
console.log(b); //⑥ 输出2
3. 不写var就自动成全局变量
// var a, 相当于在全局var了一个a
function fn(){
a = 3; //这个a第一次赋值的时候,并没有var过
// 所以就自动的在全局的范围帮你var了一次
}
fn();
console.log(a);
这是JS的一个机理,如果遇见了一个标识符,从来没有var过,并且还赋值了:
num = 12;
那么就会自动帮你在全局范围内定义 var num;
4. 函数的参数,会默认定义为这个函数的局部变量
function fn(a,b,c,d){
// var a, b, c, d; 相当于在函数内部var四个变量,是局部变量
}
a, b, c, d就是一个fn的局部变量,出了fn就没有定义
5. 全局变量的作用
5.1 通信,共同操作一个变量
两个函数同时操作同一个变量,一个增加,一个减少,函数和函数通信
var num = 0;
function add(){
num++;
}
function remove(){
num--;
}
5.2 累加,重复调用函数的时候,不会重置
var num = 0;
function baoshu(){
num++;
console.log(num);
}
baoshu(); //1
baoshu();//2
baoshu();//3
如果num定义在baoshu里面,每次执行就会把num重置为0,
function baoshu(){
var num = 0;
num++;
console.log(num);
}
baoshu(); //1
baoshu();//1
baoshu();//1
6.函数的定义也有作用域
//这个函数返回a的平方加b的平方
function pingfanghe(a,b){
return pingfang(a) + pingfang(b);
//返回m的平方
function pingfang(m){
return Math.pow(m,2)
}
}
// 现在相求4的平方,想输出16
pingfang(4); //报错,因为全局作用域下,没有一个函数叫做pingfang
机理:
function big{
function small{
}
small();//可以运行
}
small(); //不能运行,因为小small函数定义在了big函数里面,离开big函数没有作用域
二.闭包
1. 闭包
function outer(){
var a =33;
function inner(){
console.log(a);
}
return inner;
}
var inn = outer();
inn(); //弹出33
推导过程:
inner()这个函数不能在outer外面调用,因为outer外面没有inne的定义
function outer(){
var a = 88;
function inner(){
console.log(a);
}
}
//在全局调用inner 但是全局没有inner定义,所以会报错
inner();
但是我们现在就想在全局作用域下,运行outer内部的inner,此时我们必须想一些奇奇怪怪的方法。
有一个简单可行的办法,就是让outer自己return掉inner:
function outer(){
var a = 3;
function inner(){
console.log(a);
}
return inner;//outer返回了inner的引用
}
var inn = outer(): //inn就是inner函数了
inn(); //执行inn,全局作用下没有a的定义
//但是函数闭包,能够把定义函数的时候的作用域的时候一起记忆住
//能够输出33
这就说明了,inner函数能够持久保存自己定义是的所处环境,并且及时自己在其他的环境被调用的时候,依然可以访问自己定义时所处环境的值
一个函数可以把它自己内部的语句,和自己声明时所处的作用域一起封装乘了一个密闭的环境,我们称之为“闭包”(Closures)
每一个函数都是闭包,每个函数天生就能记忆自己定义时所处的作用域环境。但是,我们必须将这个函数挪到别的作用域,才能更好的观察闭包。这样才能实验它有没有把作用域给“记住”
2. 闭包的性质
每次重新引用函数的时候,闭包时全新的。
function outer(){
var count = 0;
function inner(){
count++;
console.log(count);
}
return inner;
}
var inn1 = outer();
var inn2 = outer();
inn1();//1
inn1();//1
inn1();//1
inn1();//1
inn2();//1
inn2();//2
inn1();//1
无论它在何处被调用,它总是能访问它定义时所处作用域中的全部变量