js代码嵌套问题,为啥外层定义的变量内层不能使用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js代码嵌套问题,为啥外层定义的变量内层不能使用相关的知识,希望对你有一定的参考价值。

var a = 1;
(function f1 ()
alert(a);
var a = 2;
(function f2()
alert(a)
var a = 3;
(function()
alert(a);
)()
)()
)()
这段函数,能否讲解一下,为什么只有a=3能输出来,外层的都是undefined

是这样的,在js的解释器(编译机制)里的规则是这样的

在作用域中的变量声明和方法声明都会呗编译器在编译的时候,

给强制挪到第一行,在开始执行,并且变量的默认值都是 `undefined`

比如:

(function()
  //这是一个独立作用域
  var i = 0;
  var a = 1;
  alert(i + a);
)();

经过编译后的代码可能会类似这样

(function()
  var i , a;//变量的声明会挪到首行,并且变量默认赋值为`undefined`
  i = 0;
  a = 1;
  alert(i + a);
)();

也会有这种情况

(function()
  alert(a);
  test();
  var a = 1;
  function test()
    alert('test fn');
  
)();

编译后的代码:

(function()
  var a;
  function test()//方法会直接挪到代码前
    alert('test fn');
  
  alert(a);
  test();
  a = 1;
)();

所以你会发现,定义的方法,在代码的任何位置都可以调用,就是这个原因,因为编译后的代码,不管你的方法定义在那里,都会帮你挪到首行


另外,你那里的变量,作用域的问题的规则是这样的

如果同名的变量,那么局部作用域的变量优先于外部变量

var a = 1; //这是一个外部定义的变量
(function()
  alert(a);
  var a = 2;//在这里,又使用`var`声明了一次 `a`,
            //那么这个变量就会覆盖在外面定义的变量`a`
)();

编译后的结果将是这样

var a;
a = 1;
(function()
  var a;//这里的a就会覆盖外面的变量a,并且编译器会默认赋值undefined
  alert(a);//所以这里就会弹出undefined了
  a = 1;
)();


当人,如果内部没有用`var`声明这个变量,那么外部作用域和内部的作用域就会使用同一个变量

比如这样

var a = 1;
(function()
  alert(a);//这样这个方法在自己的作用域中无法找到变量`a`,就会去父作用域找变量`a`
           //如果还没找到,就在往父作用域中找,这样直到找到为止
           //或者一直找到global(全局作用域)还没找到变量`a`,
           //就会抛出一个异常(也就是报错) 'ReferenceError : `a` is not defined'
)();

追问

十分感谢!请问相关资料去哪里查找?高级程序设计里面是否有细致的讲解?我现在手头只有一本程序设计,没有权威指南.....
还有,我之前看过一个说法说:“如果之前声明并初始化了变量,重复声明时,如果不重新初始化,那么他的值不变。” 这种说法是完全错的了?

追答

我是看的`javascript 权威指南 第六版`

关于变量声明和函数作用域,还有声明提前的这块内容是在

3.9章 变量声明
3.10章 变量作用域
3.10.1 函数作用域和申明提前

在一个作用域中,重复声明一个变量是没有关系的,对变量毫无影响,只有给变量赋值的时候才会影响到这个变量的值

参考技术A f1和f2是局部函数,与a = 1不在一个作用域;
f3与a = 3在同一作用域。

python中函数嵌套循环语句时,return 如何正确使用返回值

return
会直接另函数返回,函数就运行结束了,所有该函数体内的代码都不再执行了,所以该函数体内的循环也不可能再继续运行。
如果你需要让循环继续执行,就不能return函数,而应该选用break或者continue。
break:跳出所在的当前整个循环,到外层代码继续执行。
continue:跳出本次循环,从下一个迭代继续运行循环,内层循环执行完毕,外层代码继续运行。
return:直接返回函数,所有该函数体内的代码(包括循环体)都不会再执行。
参考技术A 这个问题我测试了一下
我先定义一个变量var
g=0;
设置加载即运行,程序是有一个for循环,里面有一个鼠标事件函数,鼠标事件函数内也有个循环
然后把
console.log(g++);
这条语句放在三个地方,一个地方是for循环的大括号里,鼠标事件函数括号外,一个地方是鼠标事件函数括号里,鼠标事件内循环括号外,一个地方是鼠标事件内循环括号里
然后用浏览器打开,加载完成即运行函数,用控制台看结果。
结论是一开始运行没有触发鼠标事件函数的时候,for循环是会循环下去直至条件结束的,但因为没有触发鼠标事件,所以鼠标事件函数不会运行,但for循环的大括号里,鼠标事件函数括号外的console.log(g++);是可以运行,并会正常运行至直至条件结束。
当触发鼠标事件的时候,鼠标函数也是会正常运行,但for循环的大括号里,鼠标事件函数括号外的console.log(g++);不会运行,只会运行鼠标事件函数里面的语句。
一般来说,for循环只是充当定义多个对象的鼠标事件函数的作用,即使如果没有触发鼠标事件,也能完成循环。
参考技术B 我将你的程序复现,如果你的两个函数没有问题,s_longs函数只需加入
return
x,即可返回执行结果,结果为6行50+字符,如下图
可是你在提问中又说了,是嵌套函数,那两个函数命名相差一个s是否为笔误?同时在while循环中参数row并未参递归与计算,不知道何意?可追问后我们再交流,谢谢

以上是关于js代码嵌套问题,为啥外层定义的变量内层不能使用的主要内容,如果未能解决你的问题,请参考以下文章

js闭包

两个for循环执行顺序

Python的闭包和装饰器

如何将两个for循环嵌套使用,要求内层循环结束,外层也一起结束。

方法的调用

js闭包