通过函数作用域和块级作用域看javascript的作用域链

  

在ES6之前,javascript只有全局作用域和函数作用域。所谓作用域就是一个变量定义并能够被访问到的范围。也就是说如果一个变量定义在全局(窗口)上,那么在任何地方都能访问到这个变量,如果这个变量定义在函数内部,那么就只能在函数内部访问到这个变量。

  

全局作用域只要页面没关闭就会一直存在,而函数作用域只有在函数执行的时候才存在,执行完就销毁。且每次执行函数都会创建一个新的作用域。

  

那么什么是作用域链呢?
  在了解作用域链之前,我们先了解一个执行期上下文的概念。

  

执行期上下文:当函数执行时,会创建一个称为执行期上下文的内部对象(即AO或去),一个执行期上下文定义了一个函数的执行环境,函数每次执行时对应的执行期上下文都是独一无二的,所以每次调用一个函数都会创建一个新的执行期上下文,当函数执行完毕,所产生的执行期上下文被销毁。

  

作用域链就是函数中[[范围]]属性所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链式链接叫做作用域链。

  

作用域链更像是一种包含的关系。比如说函数的内部定义了一个函数B,所以B的定义是依赖于一个的,也就是说B在A的内部,那么B中就可以访问一个的中的变量和方法。这种一层一层向上依赖的关系就构成了作用域链。

  

为了更好理解,我们直接看例子。

        var的名字=靶∮辍?   函数fn1 () {};   函数fn2 () {   var num=10;   函数fn3 () {   var num1=10;   console.log (num);   };   返回fn3;   }   var fn4=fn2 ();      

通过函数作用域和块级作用域看javascript的作用域链

  

在上个例子我们知道,fn2执行的时候返回fn3,产生了闭包。但是一个函数执行然后返回另一个函数都会产生闭包嘛?我们来看一下。

        var的名字=靶∮辍?   函数fn1 () {};   函数fn2 () {   var num=10;   函数fn3 () {//fn3函数没有依赖fn2函数内的变量   var num1=10;   console.log (num1);   };   返回fn3;   }   var fn4=fn2 ();      

通过函数作用域和块级作用域看javascript的作用域链

  

了解了作用域链之后,我们来看一个小例子,巩固一下。

        var=10岁;   var obj={   年龄:12岁   测试:功能(){   console.log(年龄);   console.log (obj.age);   console.log (this.age);   }   }    obj.test ();      

console.log (this.age)打印出12不难理解,但是为什么console.log(年龄)不也应该打印出12嘛。

  

我们说测试执行时首先会在自己的作用域内查看有没有年龄变量,然后再沿着作用域链往上到全局作用域查找年龄变量,全局作用域下有年龄变量和数据变量,所以console.log(年龄)打印出的10,如果要打印出12则需要访问obj.age。

  

ES6的块级作用域
  

  

在ES6之后,通过让和const引入了块级作用域。即通过让和const声明的变量只在声明所在的块级作用域内有效,并且让声明的变量虽然属于全局变量,但不再属于全局对象窗口。

  

我们通过一段代码来看一下引入块级作用域后,函数的作用域链的变化。

        var=10岁;   让obj={   年龄:12岁   测试:功能(){   console.log(年龄);   console.log (obj.age);   console.log (this.age);   }   }    obj.test ();      

通过函数作用域和块级作用域看javascript的作用域链

通过函数作用域和块级作用域看javascript的作用域链