一、作用域概念、预解析规则、表达式
1、作用域概念
什么是作用域:简单说就是作用的范围,指的是函数在哪些范围内可以用,而在其他部分就不可以使用,如果需要使用就需要重新定义。
作用域的作用是什么:用来执行读或者写的操作。
2、预解析规则
script:自上而下进行解析,
函数:由里到外进行解析。
但是浏览器在执行JS代码的时候会分成两部分操作:预解析以及逐行执行代码
预解析:浏览器在开始工作的时候会先解读JS代码的关键字:比如:var function 参数等,并把解析到的内容存入一个类似仓库的地方,这个过程一般称为JS预解析。
并且,在这个阶段所有的变量,在正式运行代码之前,都会提前赋值为未定义。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title></title> <script> alert(a); var a = 1; </script> </head> </html>
代码执行结果
函数在正式运行代码之前则是整个函数块。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title></title> <script> alert(a); function a () { alert(2); } </script> </head> </html>
代码执行结果
在这个过程中如果函数和变量重名的话只会保留函数。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title></title> <script> alert(a); var a = 1; function a () { alert(2); } </script> </head> </html>
代码执行结果:
逐行解读代码:在这个阶段浏览器会一行一行的进行解读,并找到关键字然后调用预解析阶段储存在“仓库”的信息。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title></title> <script> alert(a); var a = 1; alert(a); function a () { alert(2); } alert(a); var a = 3; alert(a); function a () { alert(4); } alert(a); </script> </head> </html>
首先在这个阶段已经完成了代码的预解析,通过代码的预解析我们知道预解析的结果为 a = function a () { alert(4)},
那么上边的代码第一次弹出的一定是a = function a () { alert(4)}请看下图
当执行到第二行时(也就是 var a = 1;)这个时候由于我们对a进行了赋值,所以第三行alert的展示结果应该是1;
当执行到第四行的时候(function a () { alert(2)};)由于它又变成了函数,但是由于函数不是表达式它不会改变值,所以执行完第五行之后会弹出1;
当代码执行到第六行(var a = 3;)的时候,由于我们给变量进行了赋值,此时a=1变成了a=3;所以第七行弹出的结果为3;
当代码执行到第八行的时候(function a(){ alert();}由于函数不改变值的原则,所以第九行弹出的结果依旧为3;
最后当代码解读完毕之后这个时候“仓库”里边储存的信息就是这样的 a = 3;怎么确认这个结果就是数字呢,我们可以使用typeof进行验证
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title></title> <script> alert(a); var a = 1; alert(a); function a () { alert(2); } alert(a); var a = 3; alert(a); function a () { alert(4); } alert(a); alert(typeof a); </script> </head> </html>
执行结果为
3、表达式
在将上边的问题的时候我们遇到一个现象:就是函数不会改变值,但是表达式却可以。
首先先来总结一下表达式有哪些?
表达式:= + - * / % ++ -- ! 参数……
作用:表达式可以修改预解析的值!