神奇的函数作用域

今天发现了两个关于函数作用域的神奇例子,这里和大家分享分享:

    var a = 1;

    function foo() {
      if (!a) {
        var a = 2;
      }
      alert(a);
    };

    foo();

  

上面这段代码在运行时会产生什么结果?

我们来分析一下:

1.创建了全局变量 a,定义其值为 1
                2.创建了函数 foo
                3.在 foo 的函数体内,if 语句将不会执行,因为 !a 会将变量 a 转变成布尔的假值,也就是 false
                4.跳过条件分支,alert 变量 a,最终的结果应该是输出 1

看起来无懈可击的分析,但是实际上,结果错误。答案竟然是 2!为什么?

什么叫申明?

是指你声称某样东西的存在,比如一个变量或一个函数;但你没有说明这样东西到底是什么,仅仅是告诉解释器这样东西存在而已;

什么叫定义?

是指你指明了某样东西的具体实现,比如一个变量的值是多少,一个函数的函数体是什么,确切的表达了这样东西的意义。

所以上面的代码实际上可以写成这样:

    var a;
    a = 1;

    function foo() {
      var a;    // 关键在这里
      if (!a) {
        a = 2;
      }
      alert(a);   // 此时的 a 并非函数体外的那个全局变量
    }
    foo();

  

然后又有人会问,不是有个if吗?if不成立哪就不会为a赋值为2。

因为 JavaScript 没有块级作用域(Block Scoping),只有函数作用域(Function Scoping),所以说不是看见一对花括号 {} 就代表产生了新的作用域,和 C 不一样!

当解析器读到 if 语句的时候,它发现此处有一个变量声明和赋值,于是解析器会将其声明提升至当前作用域的顶部(这是默认行为,并且无法更改),这个行为就叫做 Hoisting。

怎样能够alert出那个a=1?

    let a;
    a = 1;

    function foo() {
      let a;    // 关键在这里
      if (!a) {
        a = 2;
      }
      alert(a);   // 此时的 a 并非函数体外的那个全局变量
    }
    foo();

  

es6的语法,javascript是有块级作用域的。

还可以通过闭包的方式实现:

  
  var a = 1;

    function foo() {
      if (!a) {
        (function() {
          var a = 2;
        }());
      };
      alert(a);
    };

    foo();

  

        第二个例子:

   
 var a = 1;
    function test() {
        foo();

        var foo = function() {
            alert(a);
        }
    }

    test();

  

这个运行的结果是什么?初略一看,alert(1),但是实际上报错。

Uncaught TypeError: foo is not a function。

为什么会这样?

提升的仅仅是变量名 foo,至于它的定义依然停留在原处。因此在执行 foo() 之前,作用域只知道 foo 的命名,不知道它到底是什么,所以执行会报错(通常会是:undefined is not a function)。这叫做函数表达式(Function Expression),函数表达式只有命名会被提升,定义的函数体则不会。

   
 var a = 1;
    function test() {
        var foo;
        foo();	         // 这个时候函数foo,只声明,未赋值。
        foo = function() {
            alert(a);
        }
    }

    test();

  

怎么改?

    
 var a = 1;
    function test() {
        var foo = function() {
            alert(a);
        }
        foo();
    }

    test();        // 1

  

这个例子也展示了函数声明与函数表达式的差别,函数申明会放到作用域的顶部,函数表达式则不会。

        最后引用很多书中的一句话:“请始终保持作用域内所有变量的声明放置在作用域的顶部”,相信现在的你对这句话应该有一个认识了。

时间: 2025-01-05 04:17:45

神奇的函数作用域的相关文章

我的读书笔记一函数作用域

函数作用域与全局作用域: var a=123; function f(){ alert(a); var a=1; alert(a); } f(); 很多人(包括我)都会觉得根据作用域来说函数内部可以访问局部变量和全局变量,运行结果应该是第一次弹出123,第二次弹出1;这是错误的. 运行的结果:第一次弹出undefined,第二次弹出1:这是因为上面的代码等价于: var a=123;function f(){ var a; //变量提升声明 alert(a); a=1; alert(a); }

javascript中函数作用域之”提升“

javascript中函数作用域之变量提升 当我们在函数内部用关键字var声明一个变量的时候,此变量的作用域限制在当前函数. 提升:在一个作用域内部,不管一个变量用var声明的位置在哪里,这个变量属于当前整个作用域,并且在当前作用域的任何位置都可以访问它.在javascript中,这种行为/现象称之为"提升",即一个变量在一个作用域的任何位置用var声明,javascript引擎都会把这些用var声明的变量"移动"到当前作用域的开始处. 谈到javascript这种

JavaScript 函数作用域的“提升”现象

在JavaScript当中,定义变量通过var操作符+变量名.但是不加 var 操作符,直接赋值也是可以的.例如 : message = "hello JavaScript ! " 即定义了一个全局变量message,并赋值 "Hello JavaScript!"--<JavaScript高级程序第三版> 如同往日一般,一群人在所谓的技术交流群里面相互斗图着.突然老王莫名的正经起来,在群里发了一道JavaScript的题目,让大家猜一猜这道题的答案. v

《你不知道的javascript》一、函数作用域和块作用域

函数中的作用域 所谓函数作用域,就是属于这个函数的全部变量都可以在整个函数的范围内使用及复用. 1 function foo(a) { 2 var b=a; 3 function bar(c){ 4 var c=b*2; 5 console.log(c); 6 } 7 bar(); //4 8 } 9 foo(3); 1 function foo(a) { 2 var b=a; 3 function bar(c){ 4 var c=b*2; 5 console.log(c); 6 } 7 bar

javascript篇-----函数作用域,函数作用域链和声明提前

在一些类似C语言的编程语言中,花括号内的每一段代码都具有各自的作用域,而且变量在声明它们的代码段之外是不可见的(也就是我们不能在代码段外直接访问代码段内声明的变量),我们称之为块级作用域,然而,不同于这类型的编程语言,javascript是没有块级作用域.取而代之的,javascript使用的是块级作用域:变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的. 在如下的所示的代码中,在不同位置定义了变量 i . j 和 k ,它们都在同一个作用域内——这三个变量在函数体内均是有定义

变量作用域&amp;函数作用域

一. 变量作用域 1)全局变量 在全局环境下声明的变量被视为全局变量. 在没有使用var进行声明的时候,变量就被定义为全局变量.在ES5的严格模式下,如果变量没有使用var来声明是会报错的. 2)局部变量 在函数体内部声明的变量被视为局部变量.其中涉及到js中的函数作用域问题. 二. 函数作用域 因为js中是没有块级作用域的概念,所谓的块级作用域就是指花括号内的的每一段代码都有其自己的作用域,但js中并不是,例如for循环中定义的变量,外界也可以访问:但是js中有函数作用域的概念,即在每一个函数

javascript的函数作用域及声明提前

废话不说:先来段代码: var scope='global';function test(){    alert(scope);        // 输出undefine:而不是global    var scope='local';      alert(scope);        // 输出local}test(); 脑算下:你可能会认为第一alert会输出global: 但是事实上第一个alert输出的是undefined: 这是怎么回事呢? 要探讨这个问题首先要解释下两个概念: 1:函

浅谈js中函数作用域问题(一)

本人学习js时间并不长,前几天,写一段js代码时,在js指定一个按钮事件的匿名函数中加入一个同级函数,具体代码可见如下: var mainOb=document.getElementById("divObject");                                        var start=document.getElementById("start"); var a=10; start.onclick=funcrion(){ functi

javascript中函数作用域和声明提前

javascript不像java等其他强类型语句,没有块级作用域(括号内的代码都有自己的作用域,变量在声明它们的代码段之外不可见)一说,但有自己的独特地方,即函数作用域. 函数作用域:变量在声明它们的函数体内以及这个函数体的任意内部函数体内是有定义的. 如下所示代码,在不同位置定义了变量i.j和k,它们都在同一个作用域内,即在函数体内均是有定义的. function test(){ var i=0; //i在整个函数体内均有定义 if(true){ var j=0; //j在整个函数体内均有定义