JavaScript代码的执行是由浏览器中的JavaScript解析器来执行的。JavaScript解析器执行JavaScript代码的时候,分为两个过程:预解析过程和代码执行过程
预解析过程:
- 把变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值。
- 把函数的声明提升到当前作用域的最前面,只会提升声明,不会提升调用。
-
变量的提升
<script>
var num = 10;
function test1(){
console.log(num);
var num = 20;
}
test1();
/*
js解析器会将上面的代码进行变量的提升:只会提升变量的声明,不会提升赋值
var num = 10;
function test1(){
var num;
console.log(num);
num = 20;
}
test1();
*/
</script>
函数的提升
<script> test2(); function test2(){ console.log("test2执行了"); } /* js解析器也会对函数的声明进行提升,提升到当前script标签的最前面 function test2(){ console.log("test2执行了"); } test2(); */ </script>
隐式全局变量的注意点
f2(); console.log(c); console.log(b); console.log(a); function f2() { var a = b = c = 9; console.log(a); console.log(b); console.log(c); } 等效于 function f2() { var a; //局部变量 a = 9; b = 9; //隐式全局变量 c = 9; //隐式全局变量 console.log(a); //9 console.log(b); //9 console.log(c); //9 } f2(); console.log(c); //9 console.log(b); //9 console.log(a); //undefined 因为a是局部变量
隐式全局变量的进一步说明
var a = 18;
b = 10;
console.log(b);
delete b;
console.log(b); //此处会报错,原因隐式全局变量的声明是可以通过delete关键字删除的。
//删除之后就没有b的定义,无法console.log()
delete a; //全局变量是不可以delete的,此处delete无效
console.log(a);
函数提升在前,变量提升在后
var a = 3;
function a(){
console.log(10);
}
console.log(a);
a();
//提升的时候,变量声明位于函数之后
等效于:
function a(){
console.log(10)
} //前
var a; //后
a = 3;
console.log(a); //3
a(); //not function
函数中出现和全局变量同名的变量 以及if中出现和全局变量同名的变量的处理方式
var tmp = new Date();
function f(){
console.log(tmp);
if(false){
var tmp = "hello";
}
}
f();
等效为:
var tmp = new Date();
function f(){
var tmp;
console.log(tmp);
if(false){
tmp = "hello";
}
}
f();
因为变量申明是在任意代码执行前处理的,在代码区中任意地方申明变量和在最开始(最上面)的地方申明是一样的。也就是说,看起来一个变量可以在申明之前被使用!这种行为就是所谓的“hoisting”,也就是变量提升,看起来就像变量的申明被自动移动到了函数或全局代码的最顶上。
注意:仅仅是申明提升了,定义并不会被提升。
函数中出现和全局变量同名的变量 以及if中出现和全局变量同名的变量的处理方式
var x = 1;
console.log(x);
if(true){
var x = 2;
console.log(x);
}
console.log(x);
等效为
var x = 1;
console.log(x);
if(true){
x = 2;
console.log(x);
}
console.log(x);
js的var变量只有全局作用域和函数作用域两种,且申明会被提升,因此实际上x只会在最顶上开始的地方申明一次,var x=2的申明会被忽略,仅用于赋值。也就是说上面的代码实际上跟下面是一致的。
匿名函数不存在预解析的问题
f1();//-----报错
var f1=function () {
console.log(a);
var a=10;
};
案例
<script>
test3();
//console.log("a=" + a);
console.log("b=" + b);
console.log("c=" + c);
function test3(){
var a=b=c=9;
/*
var a = 9; //局部变量
b = 9; //隐式全局变量
c = 9; //隐式全局变量
*/
/*
console.log(a);
console.log(b);
console.log(c);*/
}
</script>
<script>
var a = 1;
function a(){
console.log("这是a函数");
}
console.log(typeof(a));
//a(); 因为在提升的时候先提升函数,再提升变量,所以此时a就是一个number类型,无法调用函数
/*
function a(){
console.log("这是a函数");
}
var a;
a = 1;
console.log(typeof(a));
*/
</script>
<script>
var a = 1;
var a = function(){
console.log("这是a函数");
}
console.log(typeof(a));
a();
/*
var a;
a = 1;
a = function(){
console.log("这是a函数");
}
a();
*/
</script>
<script>
//全局变量
var x = 1;
console.log(x);
if(true){
var x = 2;
console.log(x);
}
console.log(x);
/*
var x = 1;
console.log(x); //1
if(true){
x = 2;
console.log(x); //2
}
console.log(x); //2
*/
</script>
<script>
console.log(f1);
f1();
var f1 = function(){
console.log("这是函数");
}
/*
var f1;
console.log(f1);
f1();
f1 = function(){
console.log("这是函数");
}
*/
</script>