js的预解析:
为什么我们用var定义一个变量a,在这行代码之前打印a却不报错,而是得到undefined?又或者函数为什么可以随意放置,在哪里调用都可以应用,这是什么原理?
其实这样的情况,都是因为JavaScript中有一种机制,就是:“预解析机制”。
1.1 预解析原理
简单来说,预解析就是——在当前作用域下,js在运行之前,会把带有var和function关键字声明的变量先声明,并在内存中安排好。然后再从上至下解析js语句。
var 预解析
js 在正常解析之前,会快速的把 script (或者 funciton )中的 var 声明及声明的名字,提升到代码块(作用域)的最前面。
function 预解析
js 在正常解析之前,会快速的把 script (或者 funciton )中的 function 及内容提升到代码块(作用域)的最前面,跟在 var 声明之后。
1.2 var声明
通过var声明的变量,进行预解析的时候:先声明变量,不管变量有没有赋值,声明时都赋值为undefined。
事例:
console.log(a); //undefined
var a = 1;
console.log(b); //undefined
var b = function(){}//注意,这是个函数表达式
事例:
第1步:
console.log(a);// undefined,此时读取变量a
var a = 10;
//解释:在执行代码之前,js会预解析代码,代码中如果有变量声明和函数声明的话,那么便将变量声明和函数声明置顶;
也就是说,以上代码在js运行中,是如下执行的:
var a;//变量声明置顶设置,但不赋值
console.log(a); //undefined
a = 10;//变量在此处赋值。
第2步:
console.log(a); //undefined
console.log(b); //undefined
var a = 10;
var b = function(){}//同样是var声明的函数进行置顶设置,但是不赋值;
第3步:
var a = 10;
var a = function(){};
console.log(a); //function (){}
相当于:
var a = 10;
a = function(){};
console.log(a); //function (){}
var定义的a,是同一个a,不会产生不同的变量,只是让a改变了值,由数值变成了函数。
反之亦然,
var a = function(){};
var a = 10;
console.log(a); //10
var声明按照赋值顺序执行,同名的var声明,后者的声明不会产生新变量,只是值会覆盖前者。
1.3 function声明
js 在正常解析之前,会快速的把 script (或者 funciton )中的 function 及内容提升到代码块(作用域)的最前面,跟在 var 声明之后。
function进行预解析的时候,不仅是声明而且还定义了函数体,在内存中会开辟一块内存空间,存储的是函数体的字符串,但是代码不会执行。只有函数调用以后才执行。
事例:
第1步
console.log(a); //打印结果不是a,而是函数a()的方法体!证明函数a跟在var声明之后被声明的。
var a = 10;
function a(){return 100;};
其实相当于:
var a;
function a(){return 100;};
a = 10;
第2步
var a = 10;
function a(){return 100;};
console.log(a); //10
解释请看上一步的代码解释。
注意:
(1) 同名的var声明和同名的函数声明(不是函数表达式,用function声明的函数),不管二者书写先后顺序,函数声明会覆盖掉var声明的变量(因为它的置顶顺序低于var声明);
(2) 同名的var声明,后者会被忽略;
(3) 同名的函数声明,后者会覆盖前面的(这只是函数声明按自上而下的顺序执行罢了)。
课堂练习,思考一下结果:
var a = 10;
function a(){return 100;};
var a = function (){return 10000;};
console.log(a);
注意问题:
(1) 预解析,不会超出script标签,前面访问不到后面的定义
(2) 后面script标签中可以访问呢前面script标签中的js,因为js是从上至下执行的。
(3) 函数内部同名变量的声明高于传入的同名参数
var a = 10;
function fn(a){
var a = 20;
console.log(a);//20
}
fn(a);
(4) 函数内参数的声明高于外部同名变量的声明。
var a = 10;
function fn(a){
console.log(a);//100
}
fn(100);
1.4 预解析应用
var a = 1;
function b(){
a = 10;
return;
function a(){
console.log(a);
}
}
b();
console.log(a);
思考,打印结果?
注意:预解析既可置顶提升变量也可以提升函数。
代码会按照如下情况执行:
var a;
function b(){//注意,函数也会提升
function a(){//注意,函数也会提升,而不是被return结束掉了。
console.log(a);
}
a = 10;//注意,作用域链的应用,它的查找顺序是由内而外,就近原则!所以虽然函数a没有被调用过,但是这里的赋值,是赋值给b函数中的a函数的!
return;
}
a = 1;
b();
console.log(a);
课堂练习:
①
var a;
function a(){
console.log(10);
}
console.log(a);
②
function a(){
console.log(10);
}
var a;
console.log(a);
③
function a() {
var b = 1;
}
console.log(a);
var a = function() {
var b = 2;
};
文章来源:https://www.cnblogs.com/mijuntao/p/15073657.html