虽然, 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);} , 因为当两个函数重名时, 遵循代码从上往下执行
逐行解读
预解析完成之后, 就是代码逐行执行了,
第一行: 会弹出 function a(){alert(4);} , 因为预解析完成之后, 被存进内存的 a 的值就是 function a(){alert(4);}
第二行: 第二行里有表达式, a 被赋了一个新的值 1 表达式会改变变量的值表达式可以改变预解析的值
第三行: a 现在被赋值为 1, 所有会弹出 1
第四行: 只是函数的声明, 并没有用到表达式, 而且也没有函数的调用, 所以不会改变 a 的值
第五行: 因为 a 的值没有变化, 所以还是 1
第六行: 使用了表达式, a 被赋了一个新的值 3
第七行: 会弹出 3
第八行: 函数的声明, 不会改变 a 的值
第九行: a 的值没有改变, 所以还是 3
通过上面的栗子, 相信大家应该对变量作用域的预解析过程有一定的了解了, 接下来, 咋们再举几个函数作用域的栗子
例 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.jb51.net/article/134473.htm