之前我写过一篇关于JavaScript中的对象的一篇文章,里面也提到了作用域链的概念,相信大家对这个概念还是没有很深的理解,并且这个概念也是面试中经常问到的,因为这个概念实在太重要了,在我们平时写代码时,也可能会因为作用域链的问题,而出现莫名其妙的bug,导致我们花费大量的时间都查找不出原因。所以我就准备单独写一篇关于作用域链的文章,来帮大家更好地理解这个概念。 首先,我们要引入一个概念,叫做执行环境(下面简称环境)。在一个执行环境中,有一个与之关联的变量对象(下面简称对象),在该对象中,储存着这个执行环境中定义的变量和函数。但这个对象只是个形式上的对象,并不能被外界所访问到。 例如,在浏览器中,我们在全局运行下列代码,那么当前的执行环境就是 那么,在javascript中,函数也会形成一个环境,例如下列的代码中,函数的内部就是一个局部的环境,与该环境关联的对象中存储着变量 看了上面两个例子,我们对执行环境应该有了一定的了解,那么这里就将引入作用域链的概念了,当代码执行在一个环境中时,会针对环境中储存变量和函数的对象创建一个作用域链,作用域链的最前端就是当前环境的对象,如果当前环境是个函数,则作用域链的下一部分就是全局的 先来看一下代码部分 首先执行了函数 我们再来看在函数外,也就是全局 这就是代码执行时,作用域链起到的作用,所以作用域链就保证了执行环境中代码对变量的有序访问。 在JavaScript中是没有块级作用域的,也就是说,由花括号或小括号封闭起来的区域内没有自己的作用域,例如这两个例子 我们可以看到, 再来看下一个例子 在使用 以上两个例子,都是因为JavaScript没有块级作用域引起的,所以有时会因为这种情况,导致一些不必要的麻烦。在ES6中,出现了使用 其实,还有一种情况,会影响变量的访问顺序,那就是在声明变量时,直接给一个未声明的变量赋值,例如这样 按照我们本文前面讲解的作用域链的知识,当执行到最后一局代码时,此时处于全局执行环境中,查询不到变量 这是因为,在我们使用 好了,对于作用域链的讲解就到这里了,相信这下大家对JavaScript中的作用域链有了很深的理解了吧,我相信,理解了这个概念,可以消除我们代码中大部分没必要的BUG。 我是前端Lpyexplore,原创不易,喜欢我的文章的点个关注,甩个赞,不嫌麻烦的评论支持一下,谢谢大家啦~引言
正文
一、执行环境
window
,也就是全局,并且与该全局环境关联的对象中存储着定义的变量fruit
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script> let fruit = 'banana' alert(fruit) </script> </body> </html>
my_favorite
;而此时全局环境window
中,也有一个与之关联的对象,该对象中存储着变量fruit
和函数 fn1
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script> let fruit = 'banana' alert(fruit) function fn1() { let my_favorite = 'apple' return my_favorite } fn1() </script> </body> </html>
二、作用域链
window
环境的变量对象。<script> let fruit = 'banana' function fn() { let color = 'red' //返回 '我最喜欢的水果是banana,我最喜欢的颜色是red' console.log('我最喜欢的水果是' + fruit + ',我最喜欢的颜色是' + color) } fn() //报错, color is undefined console.log('我最喜欢的水果是' + fruit + ',我最喜欢的颜色是' + color) </script>
fn
,此时函数内的作用域链就是这样的
我们看到,在函数 fn
中,我们使用了变量 fruit
和 color
,所以此时会从作用域链的头部开始,从第一个活动变量(本例中第一个变量对象就是函数fn的活动变量)中,寻找变量 fruit
和 color
,发现该变量对象中存在变量color
,于是就成功引用了变量color
,但是因为没有找到变量 fruit
,于是再沿着作用域链往下找到下一个变量对象(本例中第二个活动变量就是全局window的变量对象),发现该变量对象中有我们想要的变量 fruit
,则引用该变量 fruit
,同时,因为找到了需要引用的变量,就不会继续沿着作用域链继续向下寻找了。window
中,也执行了console.log('我最喜欢的水果是' + fruit + ',我最喜欢的颜色是' + color)
,此时在全局环境中的作用域链是这样的
此时也使用了变量 fruit
和 color
,所以这时会从作用域链的头部开始,找到第一个变量对象(本例中第一个活动变量就是window全局变量对象),发现该变量对象中有变量 fruit
,所以成功引用该变量对象中的 fruit
,但因为没找到变量 color
,所以继续沿着作用域链向下寻找下一个活动变量,但此时已经找到了作用域链的尾部,并没有别的变量对象了,所以也就无法找到变量 color
了,所以最后返回的就是 undefined
。在本例中我们可以看到,当代码处于全局环境中时,是没有访问函数fn
执行环境中的变量color
的权力的,这里我们可以这种现象看成是变量color
的作用域只是在函数fn
的执行环境内。三、块级作用域
if(true) { var fruit = 'banana' } console.log(fruit) //返回 banana
if
语句中的花括号内,使用 var
定义了一个变量 fruit
,按照作用域链的规则来说,外部是无法访问到该变量的,但是我们可以看到,确实返回了这个变量的值 banana
。for(var i=0; i<4; i++) { alert(i) } console.log(i) //返回4
for
语句时,我们在小括号里使用var
定义了一个临时变量i
,同样的的,在 for
循环结束以后,在外部访问该变量,也成功返回了相应的值。let
和 const
声明变量的方式,来解决了JavaScript中没有块级作用域的问题。
你们可以看我之前写的一篇关于let
和 const
声明变量的文章——还没有理解let 和 const的用法和区别吗,几百字让你立马搞懂四、其他情况
function fn() { sum = 1 + 2 } fn() console.log(sum) //返回 3
sum
,所以应当会报错 undefined
,但这里却返回了 3。var
声明变量时,会自动将该变量放到离该代码最近的活动变量中去,也就是函数fn
的活动变量中,所以在全局执行环境中的代码就无法访问到该变量。但是如果不使用var
,而是像这个例子中一样,直接给一个未定义的变量赋值,这时会自动地将该变量放到全局的活动变量中去,这就是导致本例中在全局环境中还能访问到变量sum
的原因。五、总结
结束语
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算