虽然, ES6 在我们工作中应用得越来越广泛, 但是还是很多项目保留着 ES5 的写法, 所以, 今天, 带着大家重新巩固下 ES5 下的作用域及预解析机制.
概念:
作用域: 域, 指的是一个空间, 范围, 区域, 作用指的是在域内可进行读写操作. 一个变量的作用域是程序源代码中定义的这个变量的区域.
在 ES5 中, 只存在全局和函数级作用域, 在 ES6 中, 引入了块级作用域, JS 的预解析机制大概分为两个过程: 预解析和自上而下逐行解读
预解析: JS 解析器会先把 var 定义的变量, function, 参数等一些东西存储进仓库里面 (内存). 变量 var 在正式运行之前, 都赋值为 undefined,function 函数在运行之前, 就是整个函数块
逐行解读
表达式 =,+,-,*,/,++,--,!,%.....number(), 参数都可以赋值
遇到重名的, 只留下一个, 变量和函数重名, 函数优先级高于变量, 只留下函数
函数调用 (函数是一个作用域, 遇到作用域都会按照先进行预解析, 然后逐行解读的过程执行), 先局部找参数, 局部找不到就自下向上找 (作用域链)
概念扯了一大段, 估计初学者还是有点晕乎乎, 老司机就可以提前下车了, 接下来, 咋们举几个小栗子, 结合上面的理论, 深入理解.
实践
例 1:
- alert(a); //error: a is not defined
- a = 3;
预解析
上面说过, 预解析时只会把 var , function , 参数等存储起来, 所以:
整个作用域没有找到 var function 参数
逐行解读
预解析后, 内存中存在 a 且被赋值了 underfind 整个变量, 所有, 代码执行过程中程序直接报错.
例 2:
- alert(a); //undefined
- var a = 3;
分析:
预解析
上面说过, 预解析时只会把 var , function , 参数等存储起来, 所以:
执行到第二行时, a 的值是未定义.
逐行解读
第一行: 预解析后, 内存中存在 a 且被赋值了 underfined
例 3:
- alert(a); // function a (){
- alert(4);
- }
- var a = 1;
- alert(a); // 1
- function a (){
- alert(2);
- }
- alert(a); // 1
- var a = 3;
- alert(a); // 3
- function a (){
- alert(4);
- }
- alert(a); // 3
域解析
上面说过, 预解析时只会把 var , function , 参数等存储起来, 所以:
执行到第二行时, a 的值是未定义.
执行到第四行时, a 的值是函数本身, 也就是 function a(){alert(2);}.
执行到第六行时, a 的值还是第四行时的值, 也就是 function a(){alert(2);}, 因为函数的优先级比变量高.
执行到第八行时, a 的值就变成了 function a(){alert(4);} , 因为当两个函数重名时, 遵循代码从上往下执行.
// 在此我向大家推荐一个前端全栈开发交流圈: 619586920 突破技术瓶颈, 提升思维能力
逐行解读
预解析完成之后, 就是代码逐行执行了,
第一行: 会弹出 function a(){alert(4);} , 因为预解析完成之后, 被存进内存的 a 的值就是 function a(){alert(4);}
第二行: 第二行里有表达式, a 被赋了一个新的值 1 表达式会改变变量的值. 表达式可以改变预解析的值.
第三行: a 现在被赋值为 1, 所有会弹出 1
第四行: 只是函数的声明, 并没有用到表达式, 而且也没有函数的调用, 所以不会改变 a 的值.
第五行: 因为 a 的值没有变化, 所以还是 1
第六行: 使用了表达式, a 被赋了一个新的值 3
第七行: 会弹出 3
第八行: 函数的声明, 不会改变 a 的值.
第九行: a 的值没有改变, 所以还是 3
通过上面的栗子, 相信大家应该对变量作用域的预解析过程有一定的了解了, 接下来, 咋们再举几个函数
// 在此我向大家推荐一个前端全栈开发交流圈: 619586920 突破技术瓶颈, 提升思维能力
作用域的栗子
例 4:
- var a=1;
- function fn1(){
- alert(a); //undefined
- var a = 2;
- }
- fn1();
- alert(a) //1
例 5:
- var a=1;
- function fn1(a){
- alert(a); //1
- var a = 2;
- }
- fn1(a);
- alert(a) //1
例 6:
- var a=1;
- function fn1(a){
- alert(a); //1
- a = 2;
- }
- fn1(a);
- alert(a) //1
例 7:
- var a=1;
- function fn1(){
- alert(a); //1
- a = 2;
- }
- fn1(a);
- alert(a) //2
这几个栗子想必不用在一步步分析吧, 不过就一点小改动, 可能结果就截然不同, 所以, 大家还是需要仔细琢磨下.
结语
感谢您的观看, 如有不足之处, 欢迎批评指正.
获取资料
来源: http://www.qdfuns.com/article/51117/833ef3fd95b7ef8243e19badaded8972.html