引言
让我们来看看两种函数声明方式在不同的位置调用会发生什么结果
声明式函数声明
<script> //规范写法 function foo(){ console.log("hello world"); } foo(); //hello world </script>
如果我们将foo();提前,也可以运行。
<script> foo(); //hello world function foo(){ console.log("hello world"); } </script>
这是声明式的函数声明。可以在任何位置调用。
赋值式函数声明
<script> //规范写法 var foo = function(){ console.log("hello world"); } foo(); //hello world </script>
而如果我们将foo();提前,会报类型错误(TypeError):foo is not a function;
<script> //会报错,类型错误 foo(); var foo = function(){ console.log("hello world"); } </script>
再看直接foo();的时候的情况:会报引用错误(ReferenceError):foo is not defined ;
<script> foo(); </script>
不同的声明方式,不同的调用位置,会产生不同的结果。原因是什么?这就来到了我们今天要说的预解析。
正文
JavaScript是一种解释型语言,就是在代码执行之前,先对代码进行通读和解释,然后再执行代码。也就是说,我们的js代码在运行的时候,会经历两个环节:解释代码(预览代码)和执行代码。
预解析:
1.检查你的代码有没有语法错误
2.声明提升:把所有需要与内存进行交互的行为提前
2.1 变量提升
2.2 函数提升
2.3 变量提升和函数提升两者的优先级
1.检查你的代码有没有语法错误
首先,会检查你的代码有没有语法错误,如果有语法错误,直接终止程序。换句话说,就是如果你的代码之中有语法错误,那么你的所有代码都不会执行。
如果没有语法错误,代码从上到下执行,上面的代码照样执行,即使下面的代码有引用错误等。
<script>
console.log("hello world");
console.log(a); //引用错误,但上一行的hello world 照样执行
</script>
当出现语法错误的时候 ,可以看到,第一行的 hello world 也不会执行。
<script>
console.log("hello world");
console.log(a);
function (){
} // 函数声明中没有函数名 --- 语法错误
</script>
2.声明提升:把所有需要与内存进行交互的行为提前
(把所有的内存操作集中在一起提升代码效率)
2.1 变量提升
变量声明分为两个部分: 1.变量声明 (只有这个部分提升) 2. 变量赋值
<script>
var a = 10 ;
var b = 20 ;
</script>
<script>
//声明提前
var a,b;
//在原位置,只保留赋值部分功能
a = 10 ;
b = 20 ;
</script>
如上,变量声明提前,变量赋值不提前。
再如,当将 var a = 10 ;放在后面的时候,console.log(a)的结果是 undefined;即变量声明未赋值。
<script>
console.log(a); //undefined
var a = 10 ;
</script>
声明提升也就可以解释我们引言中的:
<script>
foo(); //类型错误(TypeError):foo is not a function;
var foo = function(){
console.log("hello world");
}
</script>
当foo();放在前面的时候,后面的var foo;会提前,foo 为 undefined ,所以不能被调用。(只有函数可以调用,所以报类型错误。)
所以正确写法是在下面调用
<script>
//正确写法
var foo = function(){
console.log("hello world");
}
foo(); //hello world
</script>
2.2 函数提升
函数提升是整体提升。
所以引言中的 声明式的函数声明 在任何位置都能调用。
<script>
foo();
var foo = function(){
console.log("hello world");
}
//foo(); //hello world
</script>
2.3 变量提升和函数提升两者的优先级
有一种情况:
<script>
console.log(foo);
var foo = 10;
function foo(){
}
</script>
分析console.log(foo);可能会出现两种情况
(1)undefined ==> 表明 函数先提升,变量声明后提升
(2) 函数 ==> 表明 变量声明先提升,函数后提升
我们查看结果:
结果为函数;表明 变量声明先提升 , 函数后提升 ; 即 局部提升优先提升 , 然后整体提升 。
总结
js在预解析中,首先检查代码是否有语法错误,如果有语法错误,所有的代码都不会执行。其次,会把所有的内存操作集中在一起提升代码效率,会有声明提升。声明提升分为变量提升和函数提升,变量提升是部分提升,即只提升声明部分,而函数提升是整体提升。局部提升的优先级更高。