在一个JavaScript文件或一个JavaScript代码块的内部,浏览器会先对代码进行预处理(编译),而后再执行。浏览器
预处理会跳过执行语句,只处理声明语句,一样也是按从上到下按顺序进行的。包括变量和函数在内的全部声明都会在任何代码被执行前首先被处理。 即便声明是在调用的下方进行的,但浏览器仍然先声明再调用(执行),这个现象叫作“提高”。因此,即使一个函数的声明在下方,在前面仍然能够正常执行这个函数。函数
注意1:对于声明并赋值的语句,例如 var a = 1,在预处理阶段会把这句话拆成两句:blog
var a; a = 1;
也就是说,赋值或其余逻辑运算是在执行阶段进行的,在预处理阶段会被忽略。ip
注意2:(1)函数声明的提高优先于变量声明的提高;(2)重复的var声明会被忽略掉,可是重复的function声明会覆盖掉前面的声明。内存
在预处理阶段,声明的变量的初始值是undefined, 采用function声明的函数的初始内容就是函数体的内容。作用域
完成预处理以后,JavaScript代码会从上到下按顺序执行逻辑操做和函数的调用。io
首先咱们来看两段简短的代码console
var a=1; function func(){ console.log(a); //var a=2; console.log(a); } func();
运行结果为:在这里打印出来的a都是1编译
var a=1; function func(){ console.log(a); var a=2; console.log(a); } func();
运行结果:在这里第一个a打印出来的结果是undefined,第二个是2function
按照C/C++第个段代码输出的结果因该是1和2,为何第一个a无法输出1呢?
分析缘由:
一、在js语言中,没有相似于c语言这样的块级做用域。
二、js做用域链变量访问规则:
(1)、当前做用域内存在要访问的变量时,则使用当前做用域中的变量。
(2)、当前做用域中不存在要访问的变量时,则会到上一层做用域中寻找,直到全局做用域。
三、执行顺序:
(1)代码的检查装载阶段(预编译阶段),此阶段进行变量和函数的声明,可是不对变量进行赋值,变量的默认值为undefined。
(2)代码的执行阶段,此阶段对变量进行赋值和函数的声明。
四、看上面的代码:第一个a输出undefined。缘由:js做用域链的访问规则,当前做用域内存在要访问的变量a,因此使用当前做用域中的变量。再根据js代码的执行顺序,此时的a只是声明了而并未被赋值,默认为undefined,因此输出undefined。而第二个a,输出1,正是由于此时的a已经被声明且被赋值,因此a输出1。
在当前做用域内存在要访问的变量a,则就会使用当前做用域的变量a,只要当前做用域存在该变量便是对该变量进行了声明(即不会再用做用域外的值),直到var a=2;才是对该变量进行赋值。在代码中先是执行了console.log(a);在执行var a=2;因此此时a在该做用域内只是进行了声明还未进行赋值,因此就会输出undefined.
例子1
var hello = function(){ console.log('hello,zhangsan'); } hello(); var hello = function(){ console.log('hello,lisi'); } hello();
运行结果:
例子2
function hello(){ console.log('hello,zhangsan'); } hello(); function hello(){ console.log('hello,lisi'); } hello();
运行结果:
JavaScript执行引擎并不是一行一行地分析和执行程序,而是一段一段地分析执行的。并且在分析执行同一段代码中,定义式的函数语句会被提取出来优先执行。函数定义执行完后,才会按顺序执行其余代码。
问题:在例子2中,两次调用都会输出相同的内容“hello,lisi”。一样是声明两个相同名称的函数,为何调用的结果却不同呢?
这就是JavaScript执行顺序致使的。JavaScript执行引擎并不是一行一行地分析和执行程序,而是一段一段地分析执行的。并且在分析执行同一段 代码中,定义式的函数语句会被提取出来优先执行。函数定义执行完后,才会按顺序执行其余代码。也就是说,在第一次调用hello函数以前,第一个函数语句 定义的代码已经被第二个函数定义语句的代码覆盖了,这就是为何在例子2中第一次调用hallo时,也会输出后面定义的函数内容的缘由了。