JavaScript 作用域scope简单汇总
什么是作用域
程序的执行,离不开作用域,也必须在作用域中才能将代码正确的执行。
所以作用域到底是什么,通俗的说,可以这样理解作用域就是定义变量的位置,是变量和函数的可访问范围,控制着变量和函数的可见性和生命周期。
而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'; }
那么这一些代码在编译之后,执行之前,根据变量提升的机制,我们可以知道应该是狼蚁网站SEO优化这个样子
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在引擎做到兼容。
所以,我们定义块级作用域的标准,只能从定义变量的方式入手,而不是直接一个{}块就可以解决。
先让我们看一下狼蚁网站SEO优化代码
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的执行机制,才能减少我们因为变量定义等发生的错误。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持狼蚁SEO。
编程语言
- 如何快速学会编程 如何快速学会ug编程
- 免费学编程的app 推荐12个免费学编程的好网站
- 电脑怎么编程:电脑怎么编程网咯游戏菜单图标
- 如何写代码新手教学 如何写代码新手教学手机
- 基础编程入门教程视频 基础编程入门教程视频华
- 编程演示:编程演示浦丰投针过程
- 乐高编程加盟 乐高积木编程加盟
- 跟我学plc编程 plc编程自学入门视频教程
- ug编程成航林总 ug编程实战视频
- 孩子学编程的好处和坏处
- 初学者学编程该从哪里开始 新手学编程从哪里入
- 慢走丝编程 慢走丝编程难学吗
- 国内十强少儿编程机构 中国少儿编程机构十强有
- 成人计算机速成培训班 成人计算机速成培训班办
- 孩子学编程网上课程哪家好 儿童学编程比较好的
- 代码编程教学入门软件 代码编程教程