JavaScript作用域和作用域链

作用域

在JavaScript中并没有和大多数语言一样通过{}来形成一个作用域,JavaScript的作用域是靠函数来形成的,也就是说一个函数内定义的变量函数外不可以访问。如:

function fn(){
  var a =5;
  if(a > 2){
    var b = 5;
  }
  console.log(b);
}
fn();
console.log(a);

上述函数fn()和console.log(a)分别输出了5和报错,var a =5在fn()构建的作用域下,console.log(a)无法获取变量a的值。

作用域的优先级

当全局变量和局部变量同时存在时,优先使用局部变量,如:

var a = 1;
function fn(){
  var a =5;
  if(a > 2){
    var b = 5;
  }
  console.log(b);
}
fn();

上述函数输出为5,虽然函数声明了全局变量var a = 1,但在局部作用域中var a =5,优先使用局部作用域下的变量。

var

作用域下的变量必须在声明时加上var,否则会声明一个全局变量,如:

    function fn(){
      a = 1;
    }
    fn();
    console.log(a);

输出结果为1,所以我们在写变量声明时要避免遗漏var,防止发生局部作用域下变量变为全局变量的情况。

作用域链

用var关键字声明一个变量时,就是为该变量所在的对象添加了一个属性。
作用域链:由于js的变量都是对象的属性,而该对象可能又是其它对象的属性,而所有的对象都是window对象的属性,所以这些对象的关系可以看作是一条链,链头就是变量所处的对象,链尾就是window对象,如:

function fn() { 
var a; 
function fn2() { 
var b; 
} 
} 

变量a所在的对象是fn,fn又在window对象中,所以a的作用域链为:fn—window。
变量b所以在的对象即fn2,fn2又包含在fn中,fn2又在window对象,所以b的作用域链为:fn2--fn--window 。

函数在执行的过程中变量的获取

var a = 1
function fn1(){
  function fn2(){
    console.log(a)
  }
  function fn3(){
    var a = 4
    fn2()
  }
  var a = 2
  return fn3
}
var fn = fn1()
fn()

上面这个函数执行fn2(),fn2()作用域下没有变量a,向上层作用域寻找,得到变量a,fn2()输出2,然后执行fn3(),通过fn2()的到fn3(),返回fn3()给fn1(),最后的到fn()输出结果为2。

结论

  1. 函数在执行的过程中,先从自己内部找变量。
  2. 如果找不到,再从创建当前函数所在的作用域去找, 以此往上。
  3. 注意找的是变量的当前的状态。

你可能感兴趣的:(JavaScript作用域和作用域链)