我知道,有些人(譬如之前的我)写js的for循环时,都不习惯加上var,这当然是语法允许的。譬如下面。  

 for(i=0;i<10;i++){//就不写成: var i=0
   alert(i);
}

  但是,这真的不是个好习惯,下面我就说说为什么写Js的for循环一定要加var,否则会时不时给你带来烦人难查的bug。

  譬如现在我们要实现这样的功能:输出  

  10
  20
  30
  40
  50
  60
  70
  80
  90
  100
  通过下面code实现,WriteNumber从1到10循环,每次循环调用TenTimes方法返回10倍的索引值。 


 1 <script type="text/javascript">
2 function WriteNumber() {
3 for (i = 1; i <= 10; i++) {
4 document.write(TenTimes(i) + "<br/>")
5 }
6 }
7 function TenTimes(v) {
8 var result = 0;
9 alert(i);
10   for (i = 1; i <= 10; i++) {
11 result += v;
12 }
13 return result;
14 }
15 WriteNumber();
16 //alert(i)
17   </script>

  你会发现最终只输出了10。大家可以用下面的代码框运行测试。

<script type="text/javascript">
function WriteNumber() {
for (i = 1; i <= 10; i++) {
document.write(TenTimes(i) + "<br/>");
}
}
function TenTimes(v) {
var result = 0;
alert(i);
for (i = 1; i <= 10; i++) {
result += v;
}
return result;
}
WriteNumber();
//alert(i)
</script>

  关于在WriteNumber和TenTimes方法里加不加var,就是说是否声明索引变量i有4种情况:

  第一种情况,WriteNumber和TenTimes各有1个for循环,2个循环里均没有用var声明i索引变量。

  运行结果:会alert出1。结果只输出了10,不是我们所想要的。

  分析:执行WriteNumber时,其作用域内并没有找到声明过的变量i,直接对i进行赋值,则隐式的将i声明为全局变量,(对于函数内部未声明过的变量,如果给它赋值,会隐式的将它声明为全局变量。

循环开始,i=1,调TenTimes方法,发现TenTimes方法也没有声明过变量i ,所以TenTimes里的i就是全局变量i,就和
WriteNumber的i成了同一个。  这时line9
alert出来的自然是1了。TenTimes循环了10次,使得全局的i变成了11,自然WriteNumber就不会执行第2次循环操作了。

  验证:如果在WriteNumber();语句后加alert(i),即取消line16的注释,会发现alert出12(12=10+2个i++),证明了i此时为windows对象。

  第二种情况,WriteNumber声明了i变量,即line3: var i=1,TenTimes未声明i变量,即line10: i=1。

  运行结果:line9 alert(i)处报i未定义错误
,因为WriteNumber有声明过变量i,所以没有成为全局的i,TenTimes执行时又没有声明过i,所以报未定义。若注释掉line9,输出结
果正确。因为当TenTimes里运行到i=1时,隐式将i声明是全局变量,不影响WriteNumber里的i。WriteNumber仍然会执行10
次循环。

  验证:如果在WriteNumber();语句后加alert(i),即取消line16的注释,会发现alert出11(11=10+TenTimes里的i++),证明了此时有windows.i。

  第三种情况,WriteNumber没有声明i变量,即line3: i=1,TenTimes声明了i变量,即line10: var i=1。

  运行结果:弹出10个undefined。因为WriteNumber未声明i,隐式将i声明是全局变量,而TenTimes有声明过变量
i(补充一句,对于变量的声明都是在预编译中进行的),所以line9
alert(i)里的i不是windows.i,而是TenTimes声明的变量i,此时当然是undefined了。同时,发现输出结果正确,因为
TenTimes的i不会影响WriteNumber的全局i,WriteNumber仍然是执行了10次循环。

  第四种情况:WriteNumber和TenTimes均用var声明了i。

  运行结果:注释掉line9,不说了,好习惯,结果当然完美。

   虽然第二、三种情况输出结果是正确的,但是对i的使用很混乱,应该算是运气导致结果正确,因为刚好1个是window.i,一个是函数内部的私有变量i,使得没有冲突。

此文虽然讲的是写for循环为什么一定要加var,但其实讲的是变量的作用域(或者说变量的生命周期)。理解之后,下面的2段code运行结果你应该能准确说出答案吧。

<script type="text/javascript">
var a = 1;
function f() {
alert(a);
var a = 2;
}
f();
</script>

<script type="text/javascript">
var a = 1;
function f() {
a = 2;
alert(a);
}
f();
alert(a);
</script>

  Ps:说道coding的好习惯,想起了这个:if(a==3) 应该写成if(3==a) 。因为我们常会把==写成1个=,如果把变量写在右边时只写了1个=,就会报编译错误,这样就能及时发现错误。

js for循环,为什么一定要加var定义i变量的更多相关文章

  1. 深刻理解this的指向和var 定义的变量的问题

    一般来说,在编程语言里我们常见的变量作用域就是词法作用域与动态作用域(Dynamic Scope),绝大部分的编程语言都是使用的词法作用域.词法作用域注重的是所谓的Write-Time,即编程时的上下 ...

  2. 在函数内部定义的变量加与不加var的区别,匿名函数和有名函数内声明变量的区别

    2014年4月21日,14:49分: 原创:http://www.cnblogs.com/liujinyu/p/3678523.html 今天写天气网英文版的产品频道,maps页面的js时,偶然意识到 ...

  3. 使用var声明的变量 和 直接赋值并未声明的变量的区别

    在看JS高级程序设计时忽然想到这个问题,众所周知,直接赋值一个变量而为声明,会产生一个全局变量(或者说是全局对象的属性),但用var声明的变量 和 直接赋值而并未声明的变量 都有哪些区别呢,这是我在百 ...

  4. JS中的块级作用域,var、let、const三者的区别

    1. 块作用域{ } <script type="text/javascript"> { var a = 1; console.log(a); // 1 } conso ...

  5. ES6 js中const,var,let区别 今天第一次遇到const定义的变量

    今天第一次遇到const定义的变量,查阅了相关资料整理了这篇文章.主要内容是:js中三种定义变量的方式const, var, let的区别. 1.const定义的变量不可以修改,而且必须初始化. 1 ...

  6. let 和 var 定义变量的区别

    一.变量提升 var 存在变量提升,而 let 不存在变量提升,所以用 let 定义的变量一定要在声明后再使用,否则会报错. var //var定义的变量存在变量提升,变量会把声明提升到整个作用域的最 ...

  7. es6的let与es5的var定义变量的区别

    es6的let与es5的var定义变量的区别 自身新手第一次接触let关键字的时候,不知道let与var的区别,本能认为是一样,但非如此,比如下述的代码运行就会报错: let hello = 'hel ...

  8. JS全局变量VAR和THIS--在函数内部,加var是局部变量,不加是全局变量

    JS全局变量VAR和THIS 2011-05-23 21:43 很多人都觉得在JavaScript声明一个变量,加var和不加var没有什么区别,实际上是一个错误的观点,如果在函数外面,也就是说在wi ...

  9. js中定义变量加var与不加var的区别?

    var 不一定是用来定义局部变量的 jscript的全局变量和局部变量的分界是这样的:                  过程体(包括方法function,对象Object o ={})外的所有变量不 ...

随机推荐

  1. Unable to mount the CD/DVD image virtualbox解决方法

    转自: http://askubuntu.com/questions/321589/unable-to-mount-the-cd-dvd-image-on-the-machine-sandbox

  2. 【OpenStack】OpenStack系列13之Nova源码解析与API扩展

    学习思路 议程:代码结构-主干流程-分层架构-业务模型-数据库模型-消息模型 分布式架构:Api:横向扩展    rpc:纵向扩展 分层架构:Controller接口层.View/Manager逻辑层 ...

  3. 【leetcode】Excel Sheet Column Number

    Excel Sheet Column Number Related to question Excel Sheet Column Title Given a column title as appea ...

  4. scrapy爬虫成长日记之创建工程-抽取数据-保存为json格式的数据

    在安装完scrapy以后,相信大家都会跃跃欲试想定制一个自己的爬虫吧?我也不例外,下面详细记录一下定制一个scrapy工程都需要哪些步骤.如果你还没有安装好scrapy,又或者为scrapy的安装感到 ...

  5. javascript动态添加form表单元素

    2014年11月7日 17:10:40 之前写过几篇类似的文章,现在看来比较初级,弄一个高级的简单的 情景: 后台要上传游戏截图,截图数量不确定,因此使用动态添加input节点的方法去实现这个效果 主 ...

  6. ORACLE查询当前资产状态,和另一个数据库联查,(查询重复数据中第一条),子查询作为字段查询

    背景:ORACLE查询当前资产状态,包含资产信息(表1),资产维修状态(表2),资产报废状态(表3) 如下: 资产信息:

  7. 一个程序中关于多个osgGA::GUIEventHandler同时存在的问题

    平时使用GUIEventHandler不太注意handle()函数的返回值,觉得返回true或者false都无所谓,其实不然. 我遇到的问题是程序中一个节点添加了GUIEventHandler对象pi ...

  8. C语言实现大数据除法

    本题要求计算A/B,其中A是不超过1000位的正整数,B是1位正整数.你需要输出商数Q和余数R,使得A = B * Q + R成立. 输入格式: 输入在1行中依次给出A和B,中间以1空格分隔. 输出格 ...

  9. .net学习笔记---HttpRuntime类

    HttpRuntime在ASP.NET处理请求中负责的是创建HttpContext对象以及调用HttpApplicationFactory创建HttpApplication. 其定义如下: publi ...

  10. 二叉树学习笔记之二叉查找树(BSTree)

    二叉查找树即搜索二叉树,或者二叉排序树(BSTree),学习回顾一下有关的知识. >>关于二叉查找树 二叉查找树(Binary Search Tree)是指一棵空树或者具有下列性质的二叉树 ...