什么是作用域
程序的执行,离不开作用域,也必须在作用域中才能将代码正确的执行。
所以作用域到底是什么,通俗的说,可以这样理解:作用域就是定义变量的位置,是变量和函数的可访问范围,控制着变量和函数的可见性和生命周期。
而JavaScript中的作用域,在ES6之前和ES6之后,有两种不同的情况。
ES6之前,JavaScript作用域有两种:函数作用域和全局作用域。
ES6之后,JavaScript新增了块级作用域。
作用域的特性
在JavaScript变量提升的讨论中,我们其实是缺少了一个作用域的概念的,变量提升其实也是针对在同一作用域中的代码来说的。
对编译器的了解,让我们明白,对于一段代码【var a = 10】变量的赋值操作,其实是包含了两个过程:
1、变量的声明和隐式赋值(var a = undefined),这个阶段在编译时
2、变量的赋值(a = 10),这个阶段在运行时
先看一下如下代码:
var flag = true; if(flag) { var someStr = 'flag is true'; } function doSomething() { var someStr = 'in doSomething'; var otherStr = 'some other string'; console.log(someStr); console.log(flag); } doSomething(); for(var i = 0; i < 10; i++) { console.log(i); } console.log(i); { var place = 'i do not want to be visited'; }
那么这一些代码在编译之后,执行之前,根据变量提升的机制,我们可以知道应该是下面这个样子:
function doSomething() { // 函数优先提升 // 提升隐式赋值 var someStr = undefined; var otherStr = undefined; someStr = 'in doSomething'; otherStr = 'some other string'; console.log(someStr); console.log(flag); } // 隐式赋值和提升 var flag = undefined; var someStr = undefined; var i = undefined; var place = undefined; flag = true; if(flag) { someStr = 'flag is true'; } for(i = 0; i < 10; i++) { console.log(i); } doSomething(); console.log(i); { place = 'i do not want to be visited'; }
因为变量的提升特性,以及无块级作用域的概念,所以代码中在同一个作用域中变量和函数的定义,在编译阶段都会提升到顶部。
通过上述代码,我们大体上可以得出作用域的特性:
第一、内部作用域和外部作用域是嵌套关系。外部作用域完全包含内部作用域。
第二、内部作用域可访问外部作用域的变量,但是外部作用域不能访问内部作用域的变量,(链式继承,向上部作用域查找)。
第三、变量提升是在同一个作用域内部出现的。
第四、作用域用于编译器在编译代码时候,确定变量和函数声明的位置。
块级作用域
上述代码,在ES6+的环境中运行,也是和ES6之前是相同的结果,但是ES6不是引用了块级作用域吗,为什么大括号块内的代码还是会出现和之前一样的编译方式呢?
那么,ES6中的块级作用域到底是什么?
let & const
利用var定义的变量,具有提升的性质,可能会影响代码的执行结果。
这是var定义变量的缺陷,那么如何规避这种缺陷呢?在ES6中,设计出来了let和const来重新定变量。
但是,由于JavaScript标准定义的非常早,1995年5月JavaScript方案定义,1996年微软提供了JavaScript解决方案JScript。而网景公司为了同微软竞争,神情了JavaScript标准,于是,1997年6月第一个国际标准ECMA-262便颁布了。
C语言标准化的过程却是将近二十年后才颁布。
所以,我们以后设计的语言既要兼容var也要有自己的块级作用域,让var和let以及const在引擎做到兼容。
所以,我们定义块级作用域的标准,只能从定义变量的方式入手,而不是直接一个{}块就可以解决。
先让我们看一下下面代码:
var name = 'someName'; function doSomething(){ console.log(name); if(true) { var name = 'otherName'; } } doSomething(); 结果:undefined
产生这个结果的原因是我们函数内部的变量提升,覆盖了外部作用域的变量,也就是说,其实打印出来的值是doSomething函数中的变量声明的值。
但是这样却并不符合块级作用域的预期,如果有许多类似代码,理解起来也会相当困难。如果将代码用ES6方式改写:
let name = 'someName'; function doSomething(){ console.log(name); if(true) { let name = 'otherName'; } } doSomething(); 结果:'someName'
从运行结果看,我们真正的做到了块级作用域应该有的效果,那么let和const又是如何支持块作用域的呢?
执行上下文
先想想一下JavaScript中的一个作用域两个执行上下文中的编译过程中的环境:
变量环境:编译阶段var声明存放的位置(一个大对象)。
词法环境:我们代码书写的位置,也是let和const的初始化位置(代码按词法环境顺序执行,按照{}划分的栈结构)。
而在编译阶段,我们将var定义的变量全都在编译过程在变量环境初始化为undefined,但是用let和const定义的变量,其实他们并未在变量环境初始化,而是在词法环境初始化,也就是执行代码位置初始化。
词法环境的特点:按照{}划分的一个栈结构。
变量查找方式
JavaScript中变量查找的方式:沿着词法环境的栈顶向下查找,找不到的变量去变量环境中查找,这样就形成了先查找代码块中的变量,再查找提升之后的变量环境,这样就形成了块级作用域的概念。
上面的代码形成两种环境的情况如下:
一、全局环境的执行上下文
变量环境:函数声明function doSomething() { … }
词法环境栈:执行到let name = ‘someName';让语句name = ‘someName'入栈。
二、doSomething的执行上下文(被全局环境包裹)
变量环境:无
词法环境栈情况:执行到let name = ‘otherName',语句的时候,name = ‘other'才会入栈;
JavaScript代码执行方式
执行doSomething的时候,还未执行let name = ‘otherName',所以,此时doSomething的词法环境中并未有name = ‘otherName',这个时候查找,只能向外部作用域查找(全局作用域)
此时查找到全局作用域name = ‘someName'所以此时就打印了someName
代码接着执行到了if语句内部,才会将name = ‘otherName'入栈,但是此时因为语句已经执行完毕,所以也就无关痛痒了。
JavaScript也就通过这种方式,实现了块级别作用域。
总结
JavaScript中的作用域总的来说,分为块级作用域、函数作用域、全局作用域。
而每个作用域都会创建自身的执行上下文,每一个执行上下文又分为了变量环境和词法环境两部分。
块级作用域的实现,其实是根据定义的let和const声明的变量放置在词法环境栈中这一特性来实现。
这一特性被社区的人叫做‘暂时性死区',但是在JavaScript标准中并未有这个概念。
只有理解了作用域的概念,才能真正明白JavaScript的执行机制,才能减少我们因为变量定义等发生的错误。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!
昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。
这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。
而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?
更新日志
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]