一. 作用域

1. 全局变量与局部变量

一个变量如果定义在了一个函数里面,那么这个变量就是一个局部变量,只在这个函数里面有定义。出了这个函数,就如同没有定义过一样。

function fn(){
    var a = 3;	//定义在一个函数里面的变量,局部变量,只有在函数里面定义
    console.log(a); //打印3
}

fn();
console.log(a); //打印a is not defined

分别在函数内和函数外打印a的值,发现控制台第一次能正常打印a的值,而第二次报错:a没有被定义。
原因是a被定义在了函数fn里面,所以现在这个a变量只在函数fn里面才会生效。

如果一个变量,没有定义在任何函数中,那么它将在全部程序范围内都有定义:
也就是你在js的任何位置都能够使用它

var a = 3;	//定义在全局范围内的一个变量,全局变量,在程序任何一个地方都有定义

function fn(){
    console.log(a); //打印3
}
fn();
console.log(a); //打印3
总结:
  • 定义在函数里面的变量,叫做局部变量,只在函数里面有定义。
  • 定义在全局范围内的,没有定义在任何函数里面的,叫做全局变量,全局都有定义。
2. 作用域链

当遇见一个变量时,JS引擎会从其所在的作用域依次向外层查找,查找会在找到第一个匹配的标识符的时候停止.

function outer(){
    var a = 3;		//a的作用域是outer
    function inner(){
        var b = 5;		//b的作用域是inner
        console.log(a);	//能够正常输出3,a在本层没有定义,就往上层函数找,发现上层函数outer有定义a
        console.log(b);   //能够正常输出5,a在本层有定义
    }
    inner();
}

outer();
console.log(a);		//报错,因为a的作用域outer,没有定义在全局。

多层嵌套,如果有同名的变量,那么就会发生“遮蔽效应”:

var a = 2;		//全局变量
function fn(){
    var a = 3;         //会把外层的a遮蔽,这函数内部看不见外层的a了。
    console.log(a);	//输出3,变量在当前作用域寻找,找到了a的定义值为5
}
fn();
console.log(a);  //输出2,变量在当前作用域寻找,找到了a的定义值为1

作用域链:一个变量在被使用的时候,就会在当前层去寻找它是否被定义,如果找不到,就往上一层函数里寻找,直到找到全局变量,如果全局也没有,就报错变量没有被定义。

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();		//执行函数
console.log(a);	// 输出1
console.log(b); // 输出2
3. 没有定义的局部变量会被定义成全局变量
// var a, 相当于在全局定义了一个a
function fn(){
    a = 3;		//这个a第一次赋值的时候,并没有定义a,
    //所以就自动的在全局的范围定义a
}
fn();
console.log(a);

这是JS的一个机制,如果遇见了一个新的标识符,从来没有被定义过,并且还赋值了:

a = 1;

那么就会自动帮你在全局范围内定义var a;
所以变量最好用var定义

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();

//不能运行,因为小函数定义在了大函数里面,离开大函数没有作用域。