函数声明 和 var声明的优先级

1.变量声明 提升:

console.log(typeof a); // undefined
 
var a = 1;

console.log(typeof a); // number

  执行过程 相当于:

var a;

console.log(typeof a); // undefined

a = 1;

console.log(typeof a); // number

 

2.函数声明 提升:

  函数声明 的提升是一个 整体提升的过程

demo:

console.log(typeof a); // function
 
function a(){}
 
console.log(typeof a); // function

  如上的demo,足可以证明,这一结论;假如不是整体提升,是类似于 var变量声明的提升的方式,应该会如 var变量声明的方式的输出方式相同, 先输出 undefined,再输出 function;

3.无所谓 函数声明优先 or 变量声明优先

  那么,又来了个问题,既然 var声明 和 函数声明 都有提升机制,那么它俩的声明提升优先级是什么样子呢;

为了论证这个我在网上看了好多资料,也查了好多书籍,大家一直认为 函数声明提升 优先于 变量声明提升,但是我发现,大家的论据都不够充分;比如如下的一个论证:

a(); // 1

var a;
function a() {
    console.log(1);
}
a = function() {
    console.log(2);
}

a(); // 2

  然后,也描述了它的执行过程,相当于:

 解释 A:

function a(){
    console.log(1);
}
var a; // 遇到没有赋值的同名声明,忽略,不做操作;相当于什么都没有做

a(); // 1

a = function(){
    console.log(2);  
}

a(); // 2

  如果如上的操作的解释,也可以通过,可以论证出 “函数声明提升 优先于 变量声明提升”;但是,按如下的理解应该也是解释的通的啊:

解释 B:

// 注意 var a 和 function a声明都会在栈空间开辟存储空间,并且 是占用同一块name为 a的空间;

var a; // 此时 a 没有赋值, 是个空的栈空间值
 
function a(){ // 找到 name为a的栈空间,给它赋值 function(){console.log(1)}, 相当于覆盖
    console.log(1);
}

a(); // 1

a = function(){
    console.log(2);  
}

a(); // 2

  看到了吧,如上的 论述也是行的通的,但是论述出来的结果 是“变量声明提升 优先于 函数声明提升”;这就尴尬了。。。

其实呢,我仔细想了一下,其实 谁先声明提升的都无所谓,因为 “var a 和 function a声明都会在栈空间开辟存储空间,并且开辟的是同一块 name为 a的空间,也就是说它们用的是同一块空间”;

4.函数声明先赋值,变量声明执行到赋值语句才赋值

  因为两种声明方式共同操作一块栈空间,所以,主要看是谁先赋值的,我们再看一个例子:

console.log(typeof a); // function

var a = 1;

function a(){}

console.log(typeof a); // number

  这就看的出来了,通过上边的这个demo, 明显可以看出来,应该 函数声明先赋值的,它是在执行上下文的执行阶段一开始的时候就已经进行了赋值操作,所以 最开始 typeof a 可以得到 function;而,变量声明 是要执行到赋值语句的时候才进行的赋值,所以 最后 typeof a 得到是 number;

  如果不是这样的话,我们不妨做下假设:

  假设1:都是最早赋值,不管谁先赋值,结果如下:

/*
->var 声明;

->函数声明;

->var 赋值;

->函数赋值:

->console.log(typeof a); // function 或者 number

->console.log(typeof a); // function 或者 number
*/

  结果如上,最后输出不是同是 function 就是同是 number, 不符合正确输出;

  假设2:都是执行到赋值语句的时候才赋值,无论 两种声明 谁前谁后,结果如下:

/*
->var 声明;

->函数声明;

->console.log(typeof a); // undefined

->赋值操作:

->console.log(typeof a); // function 或者 number
*/

  结果如上,第一个输出一定都是 undefined, 不符合正确输出;

  假设3:通过 (1) 和 (2)的不通过,那么只剩下一种可能了,都是先声明,然后一个先赋值,一个到 执行语句的时候才赋值;也就推测出了我们的结论:"函数声明先赋值,变量声明直到赋值语句的时候才赋值";执行过程如下:

/*
-> a 声明;// 因为同用一个栈空间,所以无所谓谁先声明

-> 函数声明赋值

->console.log(typeof a); // function

->变量声明赋值:

->console.log(typeof a); // number
*/

  符合正确输出的结果;所以结论成立;

  其实 函数的整体提升方式就已经论证了这一点,无论是如 解释 A 函数提升优先 + 忽略未赋值的 var 声明, 还是如 解释 B变量声明提升优先 + 函数后声明覆盖var 声明,最后都是在同一个栈空间上进行的操作,并无所谓,重要的是谁先进行的赋值操作;还有就是如上的这种 变量声明和函数声明是同名的用法,尽量不要在正式开发中使用,很容易就出现难以排查的异常;

4.总结

  *->1.函数声明 和 变量声明都有声明提升机制

  *->2.函数声明 是整体提升的方式,来进行的声明提升;

  *->3.函数声明 和 变量声明,无所谓谁优先于谁,都是在预编译阶段进行的;(根据第4点的总结,也可以理解为 函数声明优先于变量声明)

  *->4.函数声明赋值 要早于 函数声明赋值

    **->.函数声明赋值,是在执行上下文的开始阶段进行的;

    **->.变量声明赋值,是在执行到赋值语句的时候进行的赋值;

  

 原创:转载注明出处,谢谢 :)

 

原文地址:https://www.cnblogs.com/cnblogs-jcy/p/8926310.html