一个有意思的js块作用域问题
1.问题
首先把问题放出来,昨天看了一个掘友发的一个问题,然后跟我同事一起研究了一下,没找出来是为什么,然后我回来一直在想为什么,然后各种找资料研究,从各个方面找为什么,比如js上下文,作用域,js垃圾回收,堆栈调用情况等等。
2.js断点调试找答案
首先如果不看上面的图,以你现在知道的js知识,你觉得打印出来应该是什么。第二张图其实打印出来的结果在意料之中,原因就是函数声明提升,没问题,但是第一张图为什么呢?这里可以发散一下思维,比如说是不是在块作用域中,变量和函数之间存在某种互相覆盖的问题啊,或者说先在块中声明的会被挂载到全局的window对象下面,后面声明的就挂载不上去了,并且不会覆盖,然后可以把代码稍微改改,验证一下你的思想,很有意思。然后下面我们断点调试看下:
此时我们再看a在块作用域中就已经是方法了,注意此时我function a(){}这段代码还没走完呢,这就说明函数声明在js解析(注意是解析不是执行)的时候被提升到了代码块顶部,进花括号的那一刻起,函数就已经被声明了,我们再往下面一步走
此时a不管在块作用域还是全局作用域中都变成了a函数,那这里是不是可以理解为运行上面一行代码,然后就给全局变量下的a赋值为函数呢,我们再看下一步
当a=50;走完之后,也就出了块作用域,此时我们看到没有了块作用域,因为已经出了块作用域了,然后全局对象window里面a还是函数,并不是50,但是如果你在块作用域a后面加一行的断点看的话,此时块作用域里面的a的值为50,问题就在这里,为什么此时块作用域里面的a的值跟全局window对象下面的值结果不一样呢?
然后我们再往下走一步:
然后进第二个块作用域,发现跟前面进第一个块作用域一样,还没执行第一行,块作用域里面的b已经是函数了,原因也跟第一个一样js解析的时候函数声明提升,然后我们再往下走一步:
这一步走完我们发现块作用域里面的b已经变成50了,但是全局window对象下面的b还是undefined,这我也不知道为什么,那我也就只能说此时b是定义在块作用域中的内部变量了,再往下走一步
但是当我走出块作用域的时候,b竟然在全局对象下变成了50,那就证明我上面说的不对,b不是块作用域中的内部变量,因为此时执行完方法立马就出块作用域了,我们看的不是很清楚,我们在方法下面加一行代码,方便调试看结果:
确实是当我b函数那一步走完,块作用域和全局对象window下面的b都变成了50,那我这里我就认为是函数b在js解析的时候就被提升到了块作用域的最上面,执行到b函数那一步其实在之前就已经执行过了,相当于js执行的时候代码变成下面这样:
{
function b() {};
b = 50;
}
我们再看这个代码不正是上面a那一个块作用域的代码吗,所以在块作用域中js执行的时候上下两个块作用域中是一样的,所以在块作用域中打印a,b得到的结果都是50,然后下一步:
出了块作用域,就只有全局对象window了,然后window对象下面的b还是50,所以最后打印出来也是50。走到这一步就所有的步骤都走完了,那么我们再回头看上面的a为什么块作用域中的值跟window对象下面的a的值不一样,通过走完下面一个代码块我们发现上面代码块跟下面代码块只有函数放的位置不一样,结果就不一样,那我们就看一下这里函数声明提升到底是怎么提升的。
3.块作用域中的函数声明提升
然后我就找到阮一峰博客里面写的关于es6块级作用域的文章:
http://es6.ruanyifeng.com/#docs/let#%E5%9D%97%E7%BA%A7%E4%BD%9C%E7%94%A8%E5%9F%9F
另一篇关于js变量的生命周期的文章:
https://dmitripavlutin.com/variables-lifecycle-and-why-let-is-not-hoisted/
在第一篇文章中,看见里面有真么一段话:
一个有意思的js块作用域问题的更多相关文章
- 一个有意思的js实例,你会吗??[原创]
首先,看看下面一个js例子,你觉得会输出什么呢? function fn(a){ a(); function a(){ console.log(2); } var a = function(){ co ...
- 一个有意思的js小问题
问题:如何实现以下函数? add(2, 5); // 7 add(2)(5); // 7 第一个就不用说了,很简单,关键是看第二个,add(2)(5),可见add(2)应该返回的是一个函数,这个函数再 ...
- 混合开发的大趋势之 一个Android程序员眼中的 React.js 块级作用域 和 let
转载请注明出处:王亟亟的大牛之路 最近都有事干然后,快到月底了这个月给CSDN的博文也就两篇,想想也蛮多天没更了,那就来一篇. 老规矩,先安利:https://github.com/ddwhan012 ...
- 读书笔记-你不知道的JS上-函数作用域与块作用域
函数作用域 Javascript具有基于函数的作用域,每声明一个函数,都会产生一个对应的作用域. //全局作用域包含f1 function f1(a) { var b = 1; //f1作用域包含a, ...
- python 控制语句基础---->代码块:以为冒号作为开始,用缩进来划分作用域,代表一个整体,是一个代码块,一个文件(模块)也称为一个代码块 | 作用域:作用的范围
# ### 代码块:以为冒号作为开始,用缩进来划分作用域,代表一个整体,是一个代码块,一个文件(模块)也称为一个代码块 # ### 作用域:作用的范围 print(11) print(12) prin ...
- js私有作用域(function(){})(); 模仿块级作用域
摘自:http://outofmemory.cn/wr/?u=http%3A%2F%2Fwww.phpvar.com%2Farchives%2F3033.html js没有块级作用域,简单的例子: f ...
- You Don't Know JS: Scope & Closures (第3章: 函数 vs 块作用域)
第二章,作用域由一系列的bubbles组成.每一个都代表了一个container或bucket,装着被声明的identifiers(variables, functions).这些bubbles相互嵌 ...
- ES6中块作用域之于for语句是怎样的?
在ES6中新加了快作用域的概念(C语言就有,作为类c语言的js,当然应该加上),算是很好理解. { let i; } console.log(i);// i is not defined 在代码块当中 ...
- JS的作用域和作用域链
每个函数都有自己的作用域,当执行流进入一个函数时,函数就会被推入栈中,而在函数执行之后,栈将其执行环境弹出,把控制权放回给之前的作用域,全局作用域是最外围的一个作用域,因此,所有全局变量和函数都是作为 ...
随机推荐
- Linux--进程管理--06
1.操作系统的基础 调用:kernel通过给应用程序提供system call的方式来提供硬件资源: 注意:应用程序也包括库文件 库文件是运行在ring0上的一段程序代码,不对客户直接提供应用 2.程 ...
- HDU 6313
题意略. 思路:数论题. #include<bits/stdc++.h> using namespace std; ; const int maxn = p * p; ][maxn + ] ...
- testlink+vertrigoServ搭建测试用例管理系统
1.testlink简介 Testlink是一个开源的基于web的测试用例管理系统,主要功能是测试用例的创建.管理和执行,并且提供了一些简单的统计功能. 目前的公司没有专用的测试用例管理系统,为了测试 ...
- BZOJ2038 小Z的袜子 莫队
BZOJ2038 题意:q(5000)次询问,问在区间中随意取两个值,这两个值恰好相同的概率是多少?分数表示: 感觉自己复述的题意极度抽象,还是原题意有趣(逃: 思路:设在L到R这个区间中,x这个值得 ...
- 洛谷 题解 P3871 【[TJOI2010]中位数】
这题先定义一个大根堆(maxn)维护mid(n为奇数mid+1)的元素.再定义一个小根堆(minn)维护mid(n为奇数mid+1)到n的元素.然后对于插入元素的情况进行分类讨论. 当add x时 一 ...
- js中的循环方式及各种遍历的方法
for循环 1.for有三个表达式:①声明循环变量:②判断循环条件:③更新循环变量:三个表达式之间,用;分割, for循环三个表达式都可以省略,但是两个“;”缺一 不可. 2.for循环的执行特点: ...
- 文档打印 js print调用打印dom内容
1.首先按目前研究 print可以打印dom 2.被设置overflow:hidden 的模块,打印时会被截掉. 3.被设置成 display:none 的dom 打印不会有样式 边框等. 4.如果需 ...
- mybatis foreach批量处理
---恢复内容开始--- http://blog.csdn.net/jiesa/article/details/52185617 foreach属性 属性 描述 item 循环体中的具体对象.支持属性 ...
- (一)ArrayList集合源码解析
一.ArrayList的集合特点 问题 结 论 ArrayList是否允许空 允许 ArrayList是否允许重复数据 允许 ArrayList是否有序 有序 ArrayList是否线程安全 ...
- JDK1.8的HashMap数据结构及红黑树
在JDK1.6,1.7中,HashMap的实现都是用基础的“拉链法”去实现,即数组+链表的形式.如下图:通过不同的hash值,来对数据进行分配存储. 关于HashMap的Entry长度,可以参考htt ...