js中的声明提前

只要是写过点JS代码,很简单一个var 就完事了。那对于JS编译器背后它又发生了什么呢?那就一步步通过代码来讲起。


x = 1;

alert(x);
var y = function() {
  alert(x);
  var x = 2;
  alert(x);
}

y();

上面的代码也会你答对了它会分别输出:1,undefined,2。对于我来说,第一反应它会输出:1,1,2。为什么第二个会输出undefined?在上面我明确定义了一个全局变量x,为何找不到?

那是因为:js编译器在执行这个y函数的时候,会把把它body里面的声明变量提前到最前面进行声明。比如:var x=2; 编译器先会在body最前面进行var x 声明。其实上面的代码等同于下面的这段代码:

x = 1;
alert(x);
var y = function() {
  var x; //此时x还未赋值,所以为undefined。
  alert(x);
  x = 2;
  alert(x);
}
y();

所以也就不难理解x=undefined的了.但是如果把var x = 2;这段代码给删掉,在内部它没有进行var声明。它会一直沿着作用域向上找,此时的x 就为全局x.

接下来再看一个更有趣的例子。

var a = 1;
function b() {
    a = 10;
    return;
}
b();
alert(a);
///
var a = 1;
function b() {
    a = 10;
    return;
function a() {}

b(); 
alert(a);

注意 : 1. 在函数b()中将去掉var声明,则变量a就会从局部变量升级为全局变量。

例子很简单。第一个例子为输出10,第二个会输出1。这是为什么呢?况且第二个例子我都return 了。按理都应当输出10才对呀!那是因为JS编译器在背后作怪。

其实JS编译器在背后会把function a() {}编译成 var a=function (){}。那么函数内局部变量a没有升级为全局变量, 外面的a些也还是1

最张alert(a) 就会显示1;

var a=1;
function fun(){console.log(0)}
function test(){
    console.log(a)      //输出undefined 
    console.log(fun)    //输出undefined 
    console.log(f)      //输出f(){} 
    if(false){
        var a=2;
        function fun(){}
    }
    function f(){}
}
test()
注意
if(){}结构中内的语句被认为是函数表达式(expression)而不是函数声明(declaration)。而提前(hoisting)只对声明起作用,表达式不行。
转载一下优秀的解答:

 
 
作者:黄一君 链接:https://www.zhihu.com/question/52098661/answer/145533650 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

在控制语句块中直接使用函数申明而不是函数表达式的方式一直都是错误的使用方式,你的问题可以分成两块来解释:

一. var定义的变量声明都会被提升至本作用域的顶部,而函数申明整体都会提升至本作用于顶部,且函数申明整体提升的优先级高于var定义的变量提升优先级。最后考虑到你的例子中使用了var而不是let定义,所以if的块级作用域并不生效,所以你的代码去除if块中声明的fun函数后实际变成了这样:

var a = 1;
function fun(){console.log(0)}
function test() {
function f() {}
var a;
   console.log(a)      //输出undefined
   console.log(f)       //输出[Function: f]
    if (false) {
        a = 2;
    }
}
test();

所以这样打印a和f的结果就比较明显了。


二.在try{}或者if(){}块中声明函数而不是函数表达式,首先这是规范禁止大家的做法,其次很多JS引擎并没有遵守规范(这么写也不会报错),但是执行的结果会有所不同:IE10以下的版本一些老旧浏览器函数会整体提升,即你的例子中console.log(fun)会输出:[Function: fun],提升方式和一中的一致:

function fun(){console.log(0)}
function test() {
    function fun() {}
    function fun1(){}
    console.log(fun)     //输出[Function: fun]
    console.log(fun1);  //输出[Function: fun1]
    if (false) {}
    try{}catch (e){}
}
test();

但是在最新的浏览器和Node环境下,if或者try块中采用这种错误的写法,只会提升函数声明,函数体定义不会提升,类似于:

function fun(){console.log(0)}
function test() {
    var fun;
    var fun1;
    console.log(fun);    //输出undefined
    console.log(fun1);  //输出undefined
    if (false) {
        fun  = function fun() {};
    }
    try{
        fun1 = function fun1(){}
    }catch (e){}
}
test();

这种不确定的结果,必然会造成隐患,因此在if或者try等块中请使用函数表达式而不是直接的函数声明~


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值