关于js中变量作用于和变量提升的那些事

来源:互联网 发布:pc端登录淘宝卖家中心 编辑:程序博客网 时间:2024/06/06 01:48

一个变量的作用域(scope)是程序源代码中定义这个变量的区域。
全局变量拥有全局作用域,在javaScript代码中任何地方都有定义的。
然而在函数内声明的变量只是在函数内部有定义,他们是局部变量,作用域也只是在局部。

在函数体内,局部变量的优先级要高于全局变量。如果在函数体内重新声明一个与局部变量重名的变量,局部变量就会覆盖全局变量的值。

 var scope="全局变量";    function checkscope(){        var scope="局部变量";        function nested(){            var scope = "嵌套作用域内的局部变量";            alert(scope);//输出:嵌套作用域内的局部变量        }        nested();        alert(scope);//输出:局部变量    }    checkscope();    alert(scope);//输出:全局变量

从上面的例子中可以看出,局部变量的作用域仅仅在函数内部,出了函数体之后,局部变量就会被销毁。
在nested()函数中,虽然又声明了一个scope,但是nested()中的scope是局部变量,只是与全局变量的名字相同,并不是全局变量,所以,虽然在该函数中把scope赋值为”嵌套作用域内的局部变量”,但这仅仅是一个与全局变量名称相同的一个变量而已,并没有改变全局变量的值。

我们可以通过以下这个例子来进一步理解函数作用域的问题。

var scope="全局变量";    function checkscope(){        var scope="局部变量";        function nested(){            scope = "嵌套作用域内的局部变量";            alert(scope);//输出:嵌套作用域内的局部变量        }        nested();        alert(scope);//输出:嵌套作用域内的局部变量    }    checkscope();    alert(scope);//输出:全局变量

看到这里是不是有一些懵逼了,这和刚才不是一样的吗,为什么第二次弹框不一样了呢?
上面这部分代码中,在nested()函数中,我们并没有用var来声明scope,所以,在这里的scope的作用域就被提升了,即我们将checkscope中的scope的值重置了,所以在输出的时候输出的结果为嵌套作用域内的局部变量。

之前学习过c或java等其他编程语言的童鞋会知道,在c语言中会有块级作用域这个概念。
C语言中块级作用域是以成对的花括号来界定的,也就是说除了函数代码块外,if、for等结构也属于块级作用域。
下面这个例子可以帮助我们理解一下:

#include <stdio.h>  int main() {      int x = 1;      printf("%d, ", x); // 1      if (1) {          int x = 2;          printf("%d, ", x); // 2      }      printf("%d\n", x); // 1  }  

在c或c++、java中,变量的作用域是由成对的花括号来界定的,比如if中的x,在if中,x的值为2。但是,当程序运行出了if花括号以后,if中的变量x的作用域就结束了,并不会对if以外的x造成影响。但是这在js中是不一样的~

弄明白了变量的作用域之后再来考虑变量提升就简单多了。

在Javascript中,函数及变量的声明都将被提升到函数的最顶部。

在js中,变量的声明会被解析器悄悄的提升到方法体的最顶部,但是需要注意的是,提升的仅仅是变量的声明,变量的赋值并不会被提升。

function foo() {      if (false) {          var x = 1;      }      return;      var y = 1;  }  function foo() {      var x, y;      if (false) {          x = 1;      }      return;      y = 1;  }  

其实上面两段代码是一模一样的。

变量的声明会被提升,赋值不会被提前。我们需要注意的是,函数的声明与变量的声明是不一样的。函数的函数体也会被一起提升。但是,函数的声明我们可以用两种方法。

function test() {      var test1 = function () { // 变量指向函数表达式          alert("this is test1!");      }      function test2() { // 函数声明 函数名为test2          alert("this is test2!");      }  }  test();

在上面这个例子中,对于test1来说,是声明了一个变量,这个变量指向这个函数表达式,所以解析是会将var test1 提升,而后面对变量的赋值不会被提升。对于test2,解析是会把整个函数体一起提升。所以如果我们在函数体的开始运行两个函数,test1报错TypeError “test1 is not a function” ,test2则会弹出this is test2!。

我们可以用这个例子加深一下理解。

<script language="javascript" type="text/javascript">        //在全局对象中声明两个全局函数,反模式      function foo()      {          alert("global foo");      }      function bar()      {          alert("global bar");      }      //定义全局变量      var v = "global var";      function hoistMe()      {          alert(typeof foo); //function          alert(typeof bar); //undefined          alert(v); //undefined          //为什么bar函数和变量v是未定义而不是全局变量中定义的相应的函数变量呢?           //因为函数里面定义了同名的函数和变量,无论在函数的任何位置定义这些函数和           //和变量,它们都将被提升到函数的最顶部。          foo(); //local foo          bar(); //报错,TypeError "bar is not a function"        //函数声明,变量foo以及其实现被提升到hoistMe函数顶部          function foo()          {              alert("local foo");          }          //函数表达式,仅变量bar被提升到函数顶部,实现没有被提升          var bar = function()          {              alert("local bar");          };          //定义局部变量           var v = "local";      }      (function()      {          hoistMe();      })();     //函数表达式和变量表达式只是其声明被提升,函数声明是函数的声明和实现都被提升。      /**由于函数提升的效果,hoistMe方法相当于     function hoistMe()     {         //函数声明,变量foo以及其实现被提升到hoistMe函数顶部         function foo()         {             alert("local foo");         }          //函数表达式,仅变量bar被提升到函数顶部,实现没有被提升(同变量提升)         var bar = undefined;         //变量声明被提升          var v = undefined;         alert(typeof foo); //function         alert(typeof bar); //undefined         foo(); //local foo         bar(); //报错,缺少对象         bar = function()         {             alert("local bar");         };        v = "local";     }     */  </script>  
1 0
原创粉丝点击