关于JavaScript中var声明变量作用域的推断


Posted in Javascript onDecember 16, 2010

一、迷思!由一段代码引发的疑惑
请看如下代码:

for(var i=0;i<3;i++) { 
console.log(j+","+k); 
for(var j=0;j<3;j++) { 
var k = j+1; 
} 
} 
console.log(i);

输出结果:
undefined,undefined
3,3
3,3
3
如果你是搞c、java等语言的,可能你会不解,为何j、k这种局部变量可以被作用域外的代码访问呢?
如果JavaScript中用var声明的变量可视为局部变量,那么能访问到这个变量的作用域就是这个变量的局部作用域。如上例,在console.log行处,依然有j、k的作用域,而循环外,依然有i的作用域。说到这里,也许我可以武断的说,JavaScript没有真正意义的局部作用域。真的吗?非也!

二、如何获得真正的局部作用域呢?一个写法引起了我的注意
大家也许看过JQuery的源码或者Ext的源码,也许会对下面的写法有点熟悉。

var a = 3,b=4; 
var exports = (function() { 
var a = 1,b=2; 
return {a:a,b:b}; 
})(); 
console.log(""+a+","+b); 
console.log(exports.a+","+exports.b);

输出结果:
3,4
1,2
很神奇的发现(其实也不神奇,大家都知道啦)函数内部是有独立作用域的,即函数内部var声明的变量,仅在函数内部可以使用。所以各框架各大师都这么写,防止自身局部变量与外界变量(外层局部变量与全局变量)冲突。
至此,我收回第一条里的武断推断,修改一下:
JavaScript以函数为界,每个函数内部拥有一个局部作用域;任何其他的块(包括普通代码块,for循环、if、while等代码块)不存在局部作用域,使用var声明的变量可以直接穿过这些代码块,可以被外部代码访问到。

三、何时报错,何时undefined?var的声明机制
看代码:

console.log(a)

输出结果:
ReferenceError: a is not defined
输出结果:
undefined
var exports = (function() { 
var a = 1,b=2; 
return {a:a,b:b}; 
})(); 
console.log(a);

输出结果:
ReferenceError: a is not defined
猜想结论:
每次JavaScript引擎执行代码时,会先扫描作用域中的所有代码(作用域中的function内部的代码不会扫描),并将所有var声明的变量记录下来,在代码执行到赋值之前,这些变量的值为undefined。此后如果访问变量时,先访问局部变量,如果没有这个局部变量就访问上一层的局部变量(如为闭包,上一层为闭包创建环境),直到访问到完全局变量。如果都没有这个变量,那么抛出异常。

四、题外话:闭包+异步,变量值错乱!如何确保异步情况下局部变量当前值的传递?
还是代码说话:

for(var i=0;i<3;i++) { 
setTimeout(function() { 
console.log(i); 
},1); 
}

输出结果:
3
3
3
为何?因为在闭包异步执行的时候,i始终访问的是外层作用域的i,由于异步了,所以在执行闭包的时候循环已经结束了,i已经为3了,故每一次打印出来的都是3。
那如何解决这个问题呢?我们需要把i转换成局部变量。
嗯,有人会有这种写法:
for(var i=0;i<3;i++) { 
var j = i; 
setTimeout(function() { 
console.log(j); 
},1); 
}

输出结果:
2
2
2
为何?
其实之前已经解释过了,其实j和i的作用域是一样的。都是外层局部变量,在异步情况下循环执行完成的时候j为2(比i少一次i++);
那该怎么办呢?(请想象某广告,(⊙v⊙))。
大家知道,函数中的参数也算函数的局部变量。那么这里有一个办法,可以将局部变量转换为函数的实参,这样就达到值传递的效果了。
for(var i=0;i<3;i++) { 
setTimeout(( 
function(j){ 
return function() { 
console.log(j); 
} 
})(i) 
,1); 
}

输出
0
1
2
其实说了这么多,代码写出来大家就差不多明白了吧,用这种匿名函数的方式去除了异步情况下变量变化的问题,不过此为本贴的题外话了。

总结:
额。不写了,我懒,哪天抽空补上。嘿嘿。
其实这些结论RFC中应该都写了吧。但是啃英文文档。。。还是算了。。自己推断了。哈哈莫见笑莫见笑

Javascript 相关文章推荐
[推荐]javascript 面向对象技术基础教程
Mar 03 Javascript
深入理解Javascript作用域与变量提升
Dec 09 Javascript
刷新页面的几种方法小结(JS,ASP.NET)
Jan 07 Javascript
js实现右下角提示框的方法
Feb 03 Javascript
利用jQuery及AJAX技术定时更新GridView的某一列数据
Dec 04 Javascript
JS使用正则截取两个字符串之间的字符串实现方法详解
Jan 06 Javascript
JS中IP地址与整数相互转换的实现代码
Apr 10 Javascript
webpack实现热更新(实施同步刷新)
Jul 28 Javascript
在Vant的基础上实现添加表单验证框架的方法示例
Dec 05 Javascript
JS实现集合的交集、补集、差集、去重运算示例【ES5与ES6写法】
Feb 18 Javascript
react组件基本用法示例小结
Apr 27 Javascript
JavaScript的一些小技巧分享
Jan 06 Javascript
jquery中动态效果小结
Dec 16 #Javascript
关于jquery append() html时的小问题的解决方法
Dec 16 #Javascript
Javascript学习笔记二 之 变量
Dec 15 #Javascript
Javascript学习笔记一 之 数据类型
Dec 15 #Javascript
iframe 父窗口和子窗口相互的调用方法集锦
Dec 15 #Javascript
jQuery Ajax使用 全解析
Dec 15 #Javascript
JQuery 应用 JQuery.groupTable.js
Dec 15 #Javascript
You might like
六酷社区论坛HOME页清新格调免费版 下载
2007/03/07 PHP
关于zend studio 出现乱码问题的总结
2013/06/23 PHP
在PHP上显示JFreechart画的统计图方法
2013/11/03 PHP
PHP 字符串长度判断效率更高的方法
2014/03/02 PHP
浅析php如何实现App常用的秒发功能
2016/08/03 PHP
laravel框架模板之公共模板、继承、包含实现方法分析
2019/08/30 PHP
PHP 数组操作详解【遍历、指针、函数等】
2020/05/13 PHP
一个页面放2段图片滚动代码出现冲突的问题如何解决
2012/12/21 Javascript
JavaScript实现256色转灰度图
2017/02/22 Javascript
javascript 面向对象function详解及实例代码
2017/02/28 Javascript
Vue 2.0+Vue-router构建一个简单的单页应用(附源码)
2017/03/14 Javascript
axios基本入门用法教程
2017/03/25 Javascript
js中变量的连续赋值(实例讲解)
2017/07/08 Javascript
深入解析nodejs HTTP服务
2017/07/25 NodeJs
JS实现中文汉字按拼音排序的方法
2017/10/09 Javascript
Vue实现双向绑定的原理以及响应式数据的方法
2018/07/02 Javascript
vue+Element-ui实现分页效果实例代码详解
2018/12/10 Javascript
node-red File读取好保存实例讲解
2019/09/11 Javascript
为Python的web框架编写MVC配置来使其运行的教程
2015/04/30 Python
实例解析Python中的__new__特殊方法
2016/06/02 Python
使用Python将数组的元素导出到变量中(unpacking)
2016/10/27 Python
python matplotlib饼状图参数及用法解析
2019/11/04 Python
python主线程与子线程的结束顺序实例解析
2019/12/17 Python
详解pytorch tensor和ndarray转换相关总结
2020/09/03 Python
Under Armour美国官网:美国知名高端功能性运动品牌
2016/09/05 全球购物
Coltorti Boutique官网:来自意大利的设计师品牌买手店
2018/11/09 全球购物
Cocopanda波兰:购买化妆品、护肤品、护发和香水
2020/05/25 全球购物
中英文自我评价常用句型
2013/12/19 职场文书
《长城和运河》教学反思
2014/04/14 职场文书
2014年村党支部工作总结
2014/12/04 职场文书
服务员岗位职责范本
2015/04/09 职场文书
男方家长婚礼致辞
2015/07/27 职场文书
四群教育工作总结
2015/08/10 职场文书
2019最新版火锅店的创业计划书 !
2019/07/12 职场文书
Python字典和列表性能之间的比较
2021/06/07 Python
浅谈redis的过期时间设置和过期删除机制
2022/03/18 MySQL