一、问题引出
代码片段一,直接定义两个变量a,编译器报错
void main()
{
int a;
int a;
}
代码片段二,用for循环也是定义了两个变量a,编译器不报错
void main()
{
for(int i=0;i<2;i++)
{
int a;
}
}
不知道大家有没有对for循环有这样的理解:for就是自动帮我们书写了花括号里的代码内容。这样想就会无法理解代码片段2为什么不报错。
二、探讨问题
代码片段1中的错误很好解释,因为在同一作用域出现了变量重名,这会导致代码运行时无法准确的找到变量(地址),编译器就不会同意我们运行这样错误的代码。
我又提出这样的问题:
既然编译器在代码片段1中找出了错误,是因为我们声明了同样的变量名,那么代码片段2中编译器没有报错,是不是因为两个变量a不在同一作用域下呢?不在同一个作用域下变量名一样是不会报错的。
回答我上面
的问题,不是o( ̄ヘ ̄o#)
在程序设计语言里面,循环是三种语言流程之一(顺序,分支,循环),这其中循环又是编程这件事中最具魅力的,它发挥了人在思维和计算机在计算方面的双方优势,体现了程序员的技巧和智慧,也体现了代码的简洁,优雅和优美。循环中最常用的应该是 for 循环,其他几种例如while,do while又基本上可以等效写成 for 循环。同时 for 循环又可以被等效改写为递归函数。本段摘自:
那么问题转变为理解函数的生命周期!
先提前解释一下,不想看细致的分析就直接看下面的简单结论就好了。
较为准确的结论:
在for(递归函数)中,这个整数类型变量a寿命只有一次for循环(一次函数调用或函数递归一次),即每次循环开始分配a的内存,本一次循环结束a的内存就被回收了,下次循环开始再重新分配一个内存,结束是回收内存,以此类推。
不准确的结论:
在for中这个int a寿命只有一次循环,即每次循环结束a就被回收了,下次循环再分配一个新的a
三、细致的理解
待完善
换一个难一点的来看
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>for循环(难死我了)</title>
</head>
<body>
<button>1</button>
<button>2</button>
<button>3</button>
<button>4</button>
<script>
p = document.querySelectorAll('button');//let i=0 //情况1与情况3一样
for(var i=0;i<4;i++){ // 换成let试试情况2 //var i=0是情况3
p[i].onclick = function(){
console.log(i);
}
}
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>for循环(难死我了)</title>
</head>
<body>
<button>1</button>
<button>2</button>
<button>3</button>
<button>4</button>
<script>
btn = document.querySelectorAll('button');//let i=0 //情况1与情况3一样
/*---------------------------------demo1---------------------------------------*/
// for(var i=0;i<4;i++){ // 换成let试试,情况2 //var i=0是情况3
// btn[i].onclick = function(){
// console.log(i);
// // [native code] 意思已经很明确了:是 native 的代码实现的 built-in 函数,而不是 JavaScript 代码
// // 已被编译为特定于处理器的机器码的代码。
// }
// }
/*----------------------------------demo2--------------------------------------*/
let i = 0;
for(let p=0;p<1;p++){
let i = 3;
btn[i].onclick = function(){
let i = 99;
console.log(i);
}
}
</script>
</body>
</html>
本案例中的个人解释:(勿喷)
借助作用域链的变量查找,变量生命周期,变量内存空间地址
情况① 直接使用变量值(代码中的参数是具体值,被编译为机器码,呈现[native code])
情况② 拿变量地址(代码中的参数是地址,被编译为机器码,也呈现[native code])
为什么采取两种方式来获取变量?
局部域(动态存储区)中的变量必然会在程序结束前被释放,而全局域(静态存储区)中的变量是在程序结束时才被释放。
试想一下,如果全采用情况①的方法,那么会出现,只拿到程序运行过程中间时刻变量的值,而设计全局变量(静态存储区变量)一般是为了拿到最后的数据。
如果采用情况②的方法,由于局部域变量(动态存储区变量)的生命周期,在执行完复合语句(花括号包括的语句)前后,局部变量被申请、赋值和释放,释放后该地址也就不再是属于那个局部变量的了,值很有可能变了。