以下为个人对JS预解析的理解,有不正确的地方,希望您能提出,欢迎访问,不喜可喷。
JS解析过程:先预解析,然后逐行的解读代码。
那么我们带着几个问题去看下面的代码,我先给出答案,在下文给出解释。
一、预先解析哪些东西?
--预先解析 var 和 function
二、预解析的顺序?
--首先是找到<script></script>标签,按照<script>块依次解析。
--按执行环境解析
--对 var 和 function 进行解析
1、先来一段小代码,简单说一下原理
<script> console.log(a); //undefined var a = 10; function fn(argument) { console.log(a); // undefined var a = 100; } fn(); </script>
这段代码中,有两个作用域:
一个是全局作用域:作用域下有 a ,fn 。
一个是fn的内部作用域: 作用域下有 argument(参数,我们将参数和函数内的局部变量同等看待),局部变量 a 。
这两个作用域就是预解析的执行环境,JS会先在全局环境中进行预解析,查找 var a 预先解析到内存,而没有给变量赋值,所以输出结果为undefined; 然后把function fn解析到内存,所以调用fn() 照常弹出结果; 在局部作用域中预解析也是一样的,先将var a预先解析到内存,并未赋值,所以输出结果为undefined;
2、接下来我们看一下变量和函数重名的时候会是什么情况?
<script> console.log(fn); // fn() var fn = 10; function fn() { var a = 100; } console.log(fn); // 10 fn(); // 报错:fn is not a function </script>
输出的结果:
为什么会是这样的结果?
是因为function预解析时会被置顶,就像是优先级高的说法;同名function预解析时会覆盖同名的var;
在解读JS时var fn=10;function fn会跳过,说以fn为10,所以执行fn()时报错 “fn is not a function” ;
3、我们现在举个例子说明一下按照<script>块依次解析的问题:
<script> alert(msg); //报错 msg is not defined //test(); //报错 test is not defined </script> <script> var msg ="123456"; function test(){ alert("1234567"); } </script>
这里有两个script块,他们是按照顺序进行预解析的,我们在第二个script块中定义的var msg,而在第一个script块中alert(msg);
显然在第一个script快中并没有预解析到一个叫msg的变量或者函数,而js又不会跨到第二个script块去解析,所以就报错msg未定义;
将两个代码块调换就是另一种结果:
<script> var msg ="123456"; function test(){ return "1234567" } </script> <script> console.log(msg); // "123456" console.log(test()); //"1234567" </script>
结果:
当第一个script块预解析完,会解析到var msg 和function test,所以当第二个script块中执行console.log(msg)和console.log(test())时;上面的js程序已经执行完毕了,自然会输出 123456 和1234567;
4、假如一个变量我们不是用var声明的呢?
<script> console.log(msg) msg ="123456"; </script>
结果:
这也是为什么我们不推荐不去使用var声明变量的原因,我们说过Js预解析是对 var 和 function 进行解析。所以这里会报错。
不知道你理解了JS预解析没有,那我们来测试一下,哈哈
<script> console.log(a); var a = 1; console.log(a); function a() { console.log(2) } console.log(a); var a = 3; console.log(a); function a() { console.log(4) } console.log(a); a(); </script>
这是不是你想要的结果呢?