JS学习之预解释

预解释(hoisting),或者有的地方翻译为变量提升,是指在当前作用域下,JS代码从上到下执行之前,浏览器会默认先把带var和function关键字的进行提前声明或者定义。

声明(declare):只声明,没有定义,如var num,此时num的默认值是undefined

定义(defined):即赋值操作。

一、var的预解释

var:预解释的时候只提前的声明,在代码执行的过程中才定义赋值。

1 var num=15;
2 console.log(num); //15

上面的代码,很显然输出15,那么看看下面的代码:

1 console.log(num); //undefined
2 var num = 15;
3 console.log(num);//15

num经过了预解释,当代码执行到第一行时,输出num的默认值undefined,执行到第二行时,才给num定义即赋值为15,执行到第三行时,输出num为15 。再看看下面的代码:

1 console.log(num);//Error:num is not defined
2 num = 12;

不带var的变量是不进行预解释的,所以代码执行到第一行就会报错。

 

二、function的预解释

注意,function的预解释和var的预解释是不太一样的

function:预解释的时候,声明和定义都完成了。

1 var num = 12;
2 function fn() {
3     console.log(num); //undefined
4     var num = 13;
5     console.log(num); //13
6 }
7 fn();

先进行全局作用域(window)下的预解释,var num,fn声明和定义,之后代码从上到下执行,给num赋值=12,因为fn在预解释的时候已经声明+定义过了,所以可以跳过声明和定义这段,直接到第7行的fn(),执行fn,此时fn函数执行,会形成一个私有作用域,在这个私有作用域中,又开始了预解释,var num,然后这个私有作用域中的代码从上到下执行,第一个次输出只声明未定义的num为undefined,第二次输出13 。

 下面总结一下预解释的一些情况:

1.不管条件是否成立,都会进行预解释:

1 if (!("a" in window)) {
2     var a = 1;
3 }
4 console.log(a);//-->undefined

window下的预解释,var a,相当于给window增加一个属性-->window.a,,代码执行,if判断"a" in window为true,取反,所以条件不成立,输出undefined。

2.只对"="左边的进行预解释,右边的是值,不进行预解释:

1 fn();//-->undefined() Error:fn is not a function
2   var fn = function () {
3   console.log(1); 
4 };

3.window下对自执行函数是不进行预解释的,自执行函数的定义和执行是一起完成的了。但是在自执行函数执行的时候,在它的私有作用域中,是要进行预解释的:

1 ;(function (num) {
2      //在私有的作用域中是要进行预解释的
3 })(100);

4.函数体中return后面的返回值不预解释,但是return后面的代码,虽然不执行,但是要预解释(有点无节操啊)

 1 function fn() {
 2     //私有作用域下的预解释:
 3     //var num;
 4     console.log(num);//undefined
 5     return function () {
 6 
 7     };
 8     var num = 12;
 9 }
10 fn();

5.关于重名变量和预解释

1 function a(x) {}
2 var a;
3 alert(a); //function a(x) {}
重名变量a又被声明了一次,浏览器在解释的时候发现已经有一个同名变量a了,就不再去重复声明了,并且在声明的时候也没有被赋值,则变量a还是保持原来的值不变,即弹出"function a(x) {}"

如果预解释的时候发现重名了,不重新的声明,但是需要重新的定义。(即后面发现是重名的变量,如果该重名变量只是声明没有定义时,可以忽略,但是该重名变量即声明,执行时又定义赋值的话,该变量的值就等于此时的赋值,比如下面的代码)
1 function b(x){return x*2; };
2 var b=9;
3 var b="abcd";
4 alert(b);//"abcd"

犀牛书上是这样说明的:

使用var语句多次声明一个同名变量是合法的并且也没有什么害处。如果重复声明语句中含有初始值,那么就会被按照普通的赋值表达式来处理。

 

 


 

原文地址:https://www.cnblogs.com/cataway/p/4874261.html