首頁  >  問答  >  主體

html5 - 看《你不知道的javascript》,自己试验了一下书中一段代码,和书中讲解的不一样

fun(); //报错TypeError
var a=true;
if(a){
    function fun() {
        console.log("1");
    }
}else{
    function fun() {
        console.log("2");
    }
}

按书中的说法,由于函数的提升,且不受条件判断控制,应该是输出2的。可是我运行却报错了。

然后我把条件控制去掉,像这样:

    fun();//2
    function fun() {
        console.log("1");
    }
    function fun() {
        console.log("2");
    }

果然,输出了2

然后,我把条件语句加上,在最后执行函数,像这样:

var a=true;
if(a){
    function fun() {
        console.log("1");
    }
}else{
    function fun() {
        console.log("2");
    }
}
fun();//1

输出1

谁能解释一下,第一个输出的原理?以及和书上的不一样,是因为浏览器升级了的缘故吗?

巴扎黑巴扎黑2721 天前312

全部回覆(6)我來回復

  • 迷茫

    迷茫2017-04-11 12:51:29

    我非常同意 @theWalker 的回答。

    首先是不赞成这种写法,然后我分享一下在 Node5 下的试验

    var a = true;
    
    fun();  // 这里输出 3
    
    if (a) {
        function fun() {
            console.log("1");
        }
    } else {
        function fun() {
            console.log("2");
        }
    }
    
    fun();  // 这里输出 1
    
    function fun() {
        console.log("3");
    }

    所以可以分析出,最下面的 .log(3) 那个函数是函数定义,上面两个是被当作函数表达式处理的。但是命名函数表达式的名称只能在函数表达式内部使用,所以这里如果是当作命名函数表达式的话,又不科学了。再做个试验,用括号强制把中间两个函数申明为函数表达式

    var a = true;
    
    fun();  // 这里输出 3
    
    if (a) {
        (function fun() {
            console.log("1");
        });
    } else {
        (function fun() {
            console.log("2");
        });
    }
    
    fun();  // 这里输出 3
    
    function fun() {
        console.log("3");
    }

    符合对命名函数表达式的判断。

    所以,目前只能是认为解释器把那句话解释成了 var fun = function fun() {....}

    回覆
    0
  • 怪我咯

    怪我咯2017-04-11 12:51:29

    这种写法不太推荐,不同浏览器执行结果不太一样。

    函数声明在条件语句内虽然可以用,但是没有被标准化,也就是说不同的环境可能有不同的执行结果,所以这样情况下,最好使用函数表达式

      // 千万别这样做!
      // 因为有的浏览器会返回first的这个function,而有的浏览器返回的却是第二个
    
      if (true) {
        function foo() {
          return 'first';
        }
      }
      else {
        function foo() {
          return 'second';
        }
      }
      foo();
    
      // 相反,这样情况,我们要用函数表达式
      var foo;
      if (true) {
        foo = function() {
          return 'first';
        };
      }
      else {
        foo = function() {
          return 'second';
        };
      }
      foo();

    函数声明的实际规则如下:
    函数声明只能出现在程序或函数体内。从句法上讲,它们 不能出现在Block(块)({ ... })中,例如不能出现在 if、while 或 for 语句中。因为 Block(块) 中只能包含Statement语句, 而不能包含函数声明这样的源元素。另一方面,仔细看一看规则也会发现,唯一可能让表达式出现在Block(块)中情形,就是让它作为表达式语句的一部分。但是,规范明确规定了表达式语句不能以关键字function开头。而这实际上就是说,函数表达式同样也不能出现在Statement语句或Block(块)中(因为Block(块)就是由Statement语句构成的)。
    在ECMAScript的语法扩展中,有一个是函数语句,目前只有基于Gecko的浏览器实现了该扩展,所以对于下面的例子,我们仅是抱着学习的目的来看,一般来说不推荐使用(除非你针对Gecko浏览器进行开发)。

    比较详细的介绍,看完应该懂了,深入理解JavaScript系列(2):揭秘命名函数表达式

    回覆
    0
  • ringa_lee

    ringa_lee2017-04-11 12:51:29

    ES2015 中已经增加了块级作用域,而 Chrome 已经实现了这个新版语法,所以if内是一个作用域。声明提前只是会提前到当前作用域的顶部,所以 fun 的定义只会提前到 if 内最前面,而不会影响外层的 fun() 执行作用域。老语法中因为没有块级作用域,示例的整个代码都在一个作用域下,所以 fun 的定义会提前到整个代码的最前面,能够影响到 fun() 的执行作用域。

    回覆
    0
  • PHP中文网

    PHP中文网2017-04-11 12:51:29

    对,浏览器升级了,Chrome 报错,Safari输出2

    回覆
    0
  • 黄舟

    黄舟2017-04-11 12:51:29

    我测试了一下在我的node v4.2.0是正常的输出2, Chrome上是会报错的.浏览器...

    回覆
    0
  • 天蓬老师

    天蓬老师2017-04-11 12:51:29

    书上说的是js标准基本是基于ECMA的,所以不同浏览器,统一浏览器不同版本都会与差异的,因为标准总是先于实现。说一,看JDKJS比较推荐在node稳定版上测试

    回覆
    0
  • 取消回覆