javaScript在执行代码时会分为两个阶段执行。
阶段一:预解析(预编译)
阶段二:在预解析结束后,代码按照从上到下的顺序依次执行。
首先,我们来看看在预解析期间,JS做了什么。
在预解析阶段,会对定义的变量(也就是加var的变量)以及函数Function进行提升。
但是这里需要注意的是,提升var变量只是对声明进行提升,并没有赋值。但是对函数的提升,不仅仅是声明,还有赋值。
练习一下:
<script>
console.log(a)
var a = 100
console.log(a)
在这里,由于JS在预解析阶段会对定义的变量的声明进行提升(并没有赋值)。所以上面的输出语句会打印出undefined
下面的输出语句则会正常打印出 100
实际上经过处理的代码会是这样:
var a
console.log(a) // undefined
a = 100
console.log(a) // 100
</script>
再来看另外一个练习:
<script>
fn() // 1
function fn(){
console.log(1)
}
这里在最上面是可以直接调用fn函数的,因为JS在处理的时候会对函数整体进行提升。(包括声明和赋值)
实际上经过处理后是这样的:
function fn(){
console.log(1)
}
fn()
</script>
继续下一个练习:
<script>
gn()
var gn = function (){
console.log(1)
}
这个时候,就会报错:gn is not a function。因为在定义gn时加上了var,导致JS只会对gn的声明进行提升
并不会对赋值进行提升。
实际上经过处理后是这样的:
var gn
gn() //gn is not a function
gn = function (){
console.log(1)
}
</script>
继续下一个练习:
<script>
console.log(i) // undefined
for(var i = 0;i < 10;i++){}
console.log(i) // 10
在for循环里定义的i是全局变量,会在执行时对i进行变量提升。所以上面输出语句输出 undefined
下面的输出语句会输出 10
</script>
继续下一个练习:
<script>
var a = 666
fn()
function fn(){
var b = 777
console.log(a)
console.log(b)
console.log(c)
var a = 888
var c = 999
}
思考一下,上面的代码会怎样输出。
答案是:undefined 777 undefined
在函数体内的变量,会提升到函数体的最上方。
并且在寻找变量时,如果全局变量以及函数体内有相同命名的变量,会优先使用函数体内的变量,所以这里的a使用的是函数体内的a。
经过处理后,代码就会变成下面这样:
function fn(){
var b
b = 777
var a
var c
console.log(a) // undefined
console.log(b) // 777
console.log(c) // undefined
a = 888
c = 999
}
</script>
继续下一个练习:
console.log(a)
a = 555
console.log(a)
此时最上方输出语句会报错,因为定义a没有加var,所以没有进行变量提升,会提示 a is not defined。报错后,后续的代码不会继续执行。
继续下一个练习:
function fn(){
a = 1
}
fn()
console.log(a) // 1
之所以会输出a = 1,是因为此时的a是全局变量。
注意:所有没有加var的变量,都是全局变量。全局变量在函数内外都可以访问。