当前位置: 秋叶网络博客 前端编程, ◊ 闭包变量作用域导致的undefined问题

闭包变量作用域导致的undefined问题

作者:秋了秋 发表时间:2016年08月14日

在JavaScript中“熟练”掌握并理解变量的作用范围非常必要,搞混变量作用域将会带来各式各样的奇葩问题,而且是难以查找的问题,尤其在复杂的代码环境中。对变量的作用范围心如明镜也能提高开发效率。什么时候我应该大肆书写变量名而不用考虑变量重复,什么时候应该谨慎处理,明白这些才能做到写代码犹如写文章,洋洋洒洒!

爆出一个我最近遇到的一个问题,就是关于局部变量后定义导致的undefined的问题,估计很少人会遇到这种情况,无意粗心就碰到了这个问题,特此我写了个简单的例子来阐述下(把它叫做“问题函数”吧):

function douwo(a,b){
   console.log("第一层:a:"+a+",b:"+b);
   var arg=arguments.length;
   $("html").click(function(){
      console.log("第二层:a:"+a+",b:"+b);
      if(arg>2){
         var b=8;
      }
   });
}
douwo(1,2);//第一层:a:1,b:2

我把闭包函数的b=8误写成了var b=8;众所周知,函数的参数相当于该函数的局部变量。上面的代码可以写成:

function douwo(){
   var a=1,b=2;
   console.log("第一层:a:"+a+",b:"+b);
   var arg=arguments.length;
   $("html").click(function(){
      console.log("第二层:a:"+a+",b:"+b);
      if(arg>2){
         var b=8;
      }
   });
}
douwo();//第一层:a:1,b:2

这是很好理解的,关键不好理解的是当点击页面的时候,打印出来的是:第二层:a:1,b:undefined 可是一个函数中变量后定义有时候也会存在,科普下(针对新手),如:

function qlq(){
   console.log(a);//undefined
   var a=8;
}

变量分声明和定义,当一个变量用var关键字的时候是声明,=赋值是定义,而在函数内变量后声明定义会把声明提前,而定义保留在原有的位置。所以上面的代码可以写成:

function qlq(){
   var a;//声明,但未赋值
   console.log(a);//undefined
   a=8;//定义,赋值
}

而函数参数都会充当局部变量在内部提前声明,所以最上面的代码可以写成:

function douwo(a,b){
   var a,b;
   console.log("第一层:a:"+a+",b:"+b);
   var arg=arguments.length;
   $("html").click(function(){
      console.log("第二层:a:"+a+",b:"+b);
      if(arg>2){
         var b=8;
      }
   });
}
douwo(1,2);//第一层:a:1,b:2

外面那层很好理解,关键在于里面那个闭包函数:

$("html").click(function(){
      console.log("第二层:a:"+a+",b:"+b);//第二层:a:1,b:undefined
      if(arg>2){
         var b=8;
      }
   });

这又要来科普下计算机对变量的查找规则了:就近原则,所谓就近原则就是首先是从函数内部查找变量,如果没有找到就往外层找,注意,外层可能是父函数,或者全局(window),如果全局都找不到那就真的不存在这个变量了。

关键难以理解的是if(arg>2){var b=8;},理论上条件不成立就不会进到这if里面去,当然就不会执行var b=8;所以上一行的打印会出来外函数的a和b,但是事实不是这样的,虽然条件不成立不会执行,但是计算机还是阅读了这段代码,就像小学老师批改周记签上“已阅”,计算机阅过之后的代码是这样子的:

function douwo(a,b){
   var a,b;
   console.log("第一层:a:"+a+",b:"+b);//第一层:a:1,b:2
   var arg=arguments.length;
   $("html").click(function(){
      var b;
      console.log("第二层:a:"+a+",b:"+b);//第二层:a:1,b:undefined
      if(arg>2){
         b=8;
      }
   });
}
douwo(1,2);

声明了但条件不成立所以没有定义,最终问题函数输出:第二层:a:1,b:undefined也就理解通了~, 这是个坑,巨大的坑!

0
除非注明,文章均由 秋叶网络博客 发布,欢迎转载。
转载请注明本文地址:http://www.mizuiren.com/455.html
目录: 前端编程, | 标签: 局部变量 undefined | 7225次阅读