JS中函数的作用域链和闭包

1
2
3
4
5
6
写作目的:
闭包算是JS的核心内容,也是一个难点。如果要真正理解闭包,还要从变量作用域说起。
首先,我们得知道,JS采用词法作用域,也就是说,函数的执行依赖变量作用域,
这个作用域是在函数定义时决定的,而不是函数调用时决定的。
为了实现这种词法作用域,JS函数对象的内部状态不仅包含函数的逻辑代码,还必须引用当前的作用域链。
如果你现在还不理解这段话,没关系,我们先从变量作用域说起。

变量作用域

区别于Java/C系的语言,JS的变量只有两种:全局变量和局部变量,对,没有块级作用域的概念。

  • 全局变量:有用全局作用域
  • 局部变量:定义在函数内部的变量和函数的参数都是局部变量,作用域在函数体内(以及其所嵌套的函数内)。

注意:

  1. 在函数体内,局部变量的优先级高于同名的全局变量。
  2. 在函数体内声明局部变量必须使用var关键字,如果不带关键字,则相当于声明了一个全局变量。

作用域链

每一段JS代码(全局代码或函数)都有一个与之关联的作用域链。这个作用域链是一个对象列表或者链表,这组对象定义了这段代码”作用域“中的变量。也就是一开始我们说的,JS函数对象的内部状态不仅包含函数的逻辑代码,还必须维护一个对当前作用域链的引用。

通俗来说,函数的作用域链是由一系列对象组成的(函数的活动对象+零个或多个上层函数的活动对象+最后的全局对象)。在函数执行的时候,会按照先后顺序从这些对象的属性中寻找函数体中用到的变量的值,函数会在定义时将他们的作用域链存储到自身的一个内部属性中。

我们来看一些例子。

1
2
3
4
5
6
7
function outer(x){
return function inner(){
return x;
}
}
var test = outer(2);
test();//返回2

以上例子结果返回2,但是变量x既不是内部函数的局部变量,也不是全局变量,怎么会返回它的值呢,为了解决这个问题,我们先来分析全局函数。看下面例子。

未完待续。。。