作用域分为以下两点
(1).全局作用域
① 在最外层函数外面定义的变量拥有全局作用域
② 所有未定义直接赋值的变量自动声明为全局作用域
③ 所有window对象的属性拥有全局变量
④ 全局作用域有很大的弊端,过多的全局变量会污染全局的命名空间,容易引起命名冲突
(2).局部作用域
① 函数作用域声明在函数内部的变量,一般只有固定的代码片段才可以访问到
② 作用域是分层的,内层作用域可以访问外层作用域,反之不行
在ES6当中还有一种特殊的叫做块级作用域
① 使用es6中新增的let和const指令可以声明块级作用域,,块级作用域可以在函数中创建也可以在一个代码块中创建(由{ }包裹的代码片段)
② let和const声明的变量不会有变量提升,也不可以重复声明
③ 在循环中比较适合绑定块级作用域,这样就可以把声明的计数器变量限制在循环内部
什么是作用域链呢 ??
在当前作用域当中查找所需变量,但是该作用域没有这个变量,那么这个变量就是自由变量,如果在自己作用域当中找不到该变量那么就去父级作用域去查找,依次向上级作用域查找,直到访问到window对象就被终止,那么在这个查找过程中会产生一个成链式连接的集合:储存着执行期上下文对象的集合,这种结构就可以成为作用域链
作用域链的作用是保证对执行环境有权访问的所有变量和函数的有序访问,通过作用域链,可以访问到外层环境的变量和函数
上文中我们有提到执行期上下文,那么什么是执行期上下文呢???
执行期上下文大致分为两类:
(1). 全局执行上下文
任何不在函数内部的都是全局执行上下文,它首先会创建一个全局的window对象,并且设置this的值等于这个全局对象,一个程序中只有一个全局执行上下文.
(2). 函数执行上下文
当一个函数被调用时,就会为该函数创建一个新的执行上下文,函数的上下文可以有任意多个
我们来看代码
那么当我们运行以上代码的时候会发生什么呢? 我们来看图
首先函数a声明的时候会产生一个[[scope]] , 其中就包含一个一个的执行上下文,这些集合就被称为 [scope chain] (作用域链) , 因为函数a定义在全局,所以一定会有一个全局执行上下文 : [Global Object] , 在全局上下文中,包含一些内置的键值对,包括this , 指向window , 以及我们定义的全局变量 global , 值为100
然后当我们执行a的时候会产生一个a的执行上下文 :
当a执行的时候(橙色线条), Go(全局执行上下文)在作用域链中会被挤到1的位置上,函数a自己的执行上下文(AO)会被挤到最顶端,也就是0的位置,这也就是为什么查找变量是由内而外, [从作用域链的最顶端开始查找]
最后当我们在函数a里面执行函数b的时候,也是相同的规则 :
红色的线条代表的就是函数b被执行的时候,0的位置存放着b的执行上下文,1的位置放着a函数a的执行上下文,2的位置上放着全局的执行上下文。