对变量提升,作用域,作用域链的最新理解

294 阅读3分钟

对变量提升,作用域,作用域链的最新理解

首先先来介绍一下什么叫做作用域链。那先来说说什么是作用域。

作用域就是代码的执行环境,全局执行环境就是全局作用域,函数的执行环境就是私有作用域,它们都是栈内存。

全局执行环境是在页面一打开时,浏览器主线程会分出一个线程来加载js代码,而在加载时会为代码执行而创建的环境,也就是我们所说的执行环境(ECStack.)

只有当有了执行环境,才开始创建全局作用域(EC{Global}),也就是我们所说的全局作用域。

当作用域准备完毕,会把全局作用域(EC{Global})拿到准备好的环境中JS代码依次至上而下执行。

在代码执行前,也还用做很多的事情,这时变量,函数需要进行一些特别的操作,变量提升,函数提前赋值声明。后续还有词法解析,当这一些列操作完毕之后,才开始至上而下的加载js代码。

变量提升

1.当变量被var 声明,在js加载时会被提前声明至全局作用域中的VO(global)中存储起来,但此时并不赋值。而后续当js代码执行的时候,当执行到被var声明的变量时,才进行赋值操作,值会存储全局作用域的(EC{Global})中存储起来,并且与变量关联

2.当时函数function fn(){}时,在变量提升阶段,它就会直接被声明并且进行赋值操作,在后续js至上而下进行加载的时候,遇到别声明赋值的函数,直接就会跳过执行,而在进行声明赋值之后,函数还有一个过程,就是给函数设置了一个fn{'scope'},这样的一个操作,这里面存储着是当前作用域。

3.let ,const等ES6声明过的没有不进行变量提升。

作用域链

执行函数的时候,它会创建一个私有的作用域,之前有人说私有的作用域和全局的作用域是有层级关系的,其实不然,它们是平级关系,为什么我会这么说呢,请听我细细道来。

我们来模拟一个场景,现在有一个执行环境(ECState),里面正有一个全局作用域正在执行,当遇到一个函数执行fn(),此时会形成一个稀有的作用域,并且拿到执行环境中代码至上而下去执行,此时私有作用域并没有拿到全局作用域体中去执行,而是拿到执行环境中去执行,这句话很重要,而全局作用域则到了执行环境最底部,私有作用域在最顶部来执行代码,从这一层关系中,我们可以查看到两者的关系是平级关系,而并非层级关系。

我们回到主题,作用域链,当在私有作用域中被创建时,也要进行如全局全局作用域中那一些操作,变量提升,词汇解析,只是在此基础上多了形参赋值,this的格式化,scopeChain:<当前私有作用域,fn('scope')>等

当这些加载完毕后,开始进行代码至上而下加载,当发现私有作用域中有未声明的变量的时候,依据scopeChain:<当前作用域,fn'scope'>中去查找上级作用域,scope中存储的上级作用域,浏览器是根据c++写出来的,在浏览器去查找上级作用域的时候就是根据scope这个标识查找里面存储的作用域。这也就是所谓的作用域链查找机制。

最后以图的形式展示:

本文为原创:浩