理解JavaScript变量作用域更轻松


Posted in Javascript onOctober 25, 2009

JavaScript本身作为一门简单的语言,就其变量作用域问题一样令不少人头晕,这主要是因为JavaScript闭包的存在。本文不打算深入讲解JavaScript变量作用域问题(其实本人也没有能力能把这一话题讲的深入些),也不讲“闭包”话题,本文只讨论最实用的JavaScript作用域知识点。

一、JavaScript作用域分类
JavaScript就两种作用域:全局(window)、函数级(function)。函数级(function)不要理解为“块级(大括号{}级)”。

二、区分及定义JavaScript全局变量与局部变量
1.1定义在所有函数最外边,使用或不使用var关键字定义的变量都是全局变量。全局变量其实被解析成window对象的一个属性,所以我们可以以“window.全局变量名”方式访问它,推荐在没有必要的情况下直接使用变量名访问。如下例子演示了全局变量定义最常见的方法:

var msg1='This is message 1'; 
msg2='This is message 2'; 
alert(window.msg1); //This is message 1 使用window关键字进行访问 
alert(window.msg2); //This is message 2 
alert(msg1); //This is message 1 省略window关键字的访问方式 
alert(msg2); //This is message 2 
function otherFunction(){} //其它一些函数或对象声明代码 
var otherObject={};

1.2在函数内(局部变量运行时环境)一样可以定义和获取全局变量。定义的方法就是不使用var关键字,而在局部环境中亦可轻松获得全局变量内容,直接使用全局变量名引用即可。需要注意的是:如果函数内定义了与全局变量同名的局部变量,那么此时函数体将优先使用自己的局部变量,如果此时你非要使用同名的全局变量,请加上window前缀。举例如下:
var msg1='This is message 1'; 
var msg3='This is message 3'; 
function otherFunction() 
{ 
msg2='This is message 2'; //不使用var关键字,其实也是定义一个全局变量 
var msg3='Message 3'; 
alert(msg1); //This is message 1 (函数内当然可以访问到外面定义的全局变量,再深的函数嵌套一样能正确获到这个全局变量,这是JavaScript闭包的其中一种体现) 
alert(msg3); //Message 3 (局部变量msg3) 
alert(window.msg3); //This is message 3 (使用window前缀访问同名的全局变量msg3) 
alert(this.msg3); //This is message 3 (因为otherFunction ()定义在一个全局的环境中,此时otherFunction ()的this也是指向window,所有你看到window. msg3是等于this. msg3的) 
} 
otherFunction(); 
//otherFunction函数外面定义的msg1和里面定义的msg2依然是全局变量 
alert(window.msg1); //This is message 1 
alert(window.msg2); //This is message 2

2.1使用var关键字,在函数体内定义的变量是局部变量,此变量能供其下面所有语句块({})及子函数使用。这个变量在这个函数里任何地方都可以访问到,但却不能在这个函数的外面“直接”访问(闭包允许间接访问,或代理访问,此知识点不在本文讨论范围)。举例如下:
function showMsg() 
{ 
if (true) 
{ 
var msg='This is message'; 
} 
alert(msg); //This is message 
} 
showMsg(); 
alert(typeof(msg)); //undefiend 
//这里在if {}大括号内定义的变量msg还能在if外showMsg()内访问到,但在showMsg()外则是无法访问的

2.2父函数的变量可以被子函数访问,但子函数的变量却不能被父函数访问,显然这与我们一开始说的函数级作用域是相吻合的。这看起来老爸爽快些,儿子吝啬些。举例如下:
function showMsg() 
{ 
var MsgA='Message A'; 
this.setMsg=function(msg) 
{ 
var MsgB='Message B'; 
alert(MsgA); //Message A (子函数setMsg()可以访问父函数showMsg()的局部变量MsgA) 
} 
alert(MsgB); //MsgB未定义 (在父函数中不能访问其子函数中定义的变量MsgB) 
} 
var sm=new showMsg(); 
sm.setMsg('Message string');

三、需要注意的几个地方及使用技巧
1、为了避免变量混乱或被覆盖,对于局部变量的定义一定不要忘记加上var关键字(必要时我们要变量使用完后主动释放它,即“变量名=null”),同时建议把所有变量集中定义在每个函数体内的开头位置。举例如下:
var msg='Message'; 
function showMsg() 
{ 
var msg; //这里即使不小心使用了与全局变量一样的变量名,也不用担心覆盖同名全局变量的问题 
var a; 
var b; 
var c; 
for (a=0;a<10;a++){} 
this.setMsg=function(){} 
}

2、巧用匿名函数,减少命名冲突或变量污染。如下两段代码其实实现了相同的功能,而第一段代码写法自己可以在那个匿名函数内大胆用自己想用的变量名等,不用担心自己定义的变量覆盖其他人定义或自己其它地方定义的变量。
//定义一个匿名函数,然后把代码丢到这个匿名函数里面,能有效减少命名冲突或变量污染,这是常见JS框架的做法 
(function() 
{ 
var msg='This is message'; 
alert(msg); 
})(); 
document.write(msg); //msg未定义 (匿名函数外的其它方法已无法调用msg这个变量) 
//----------------------------- 
var msg='This is message'; 
alert(msg);

3、不建议在无须实例化的函数内使用this代替window去访问全局变量。一般情况使用this关键字的函数应当作为JavaScript类来处理(我喜欢把“cls”作为类名的前缀)。以下函数如果仅当作普通函数调用一下,就不应该出现this关键字,因为这通常是去操作一个全局变量了。例子:
function clsMsg() 
{ 
this.msg='This is default message'; 
this.showMsg=function() 
{ 
alert(this.msg); 
} 
} 
sMsg=new clsMsg(); 
sMsg.msg='This is new message'; 
sMsg.showMsg();

四、相关知识点指引
理解以下相关知识点有助于你更好地认识JavaScript变量作用域,本文暂不详述,随后会以单独篇幅来讲,敬请关注。
(1)理解JavaScript“预解析”
(2)JavaScript闭包
Javascript 相关文章推荐
jQuery开发者都需要知道的5个小技巧
Jan 08 Javascript
JavaScript截取字符串的2个函数介绍
Aug 27 Javascript
JavaScript实现的浮动层框架用法实例分析
Oct 10 Javascript
JavaScript必知必会(十) call apply bind的用法说明
Jun 08 Javascript
利用js获取下拉框中所选的值
Dec 01 Javascript
JavaScript两个变量交换值的实现方法
Mar 01 Javascript
微信小程序页面传值实例分析
Apr 19 Javascript
EasyUI在Panel上动态添加LinkButton按钮
Aug 11 Javascript
jQuery实现的监听导航滚动置顶状态功能示例
Jul 23 jQuery
javascript使用链接跨域下载图片
Nov 01 Javascript
vue prop属性传值与传引用示例
Nov 13 Javascript
Javascript摸拟自由落体与上抛运动原理与实现方法详解
Apr 08 Javascript
理解 JavaScript 预解析
Oct 25 #Javascript
WEB页子窗口(showModalDialog和showModelessDialog)使用说明
Oct 25 #Javascript
JavaScript弹簧振子超简洁版 完全符合能量守恒,胡克定理
Oct 25 #Javascript
javascript window对象属性整理
Oct 24 #Javascript
Javascript 模式实例 观察者模式
Oct 24 #Javascript
Jquery 弹出层插件实现代码
Oct 24 #Javascript
js 操作符实例代码
Oct 24 #Javascript
You might like
推荐一款MAC OS X 下php集成开发环境mamp
2014/11/08 PHP
PHP调试的强悍利器之PHPDBG
2016/02/22 PHP
PHP使用自定义方法实现数组合并示例
2016/07/07 PHP
thinkphp 抓取网站的内容并且保存到本地的实例详解
2017/08/25 PHP
JavaScript DOM 学习第七章 表单的扩展
2010/02/19 Javascript
基于jquery的图片的切换(以数字的形式)
2011/02/14 Javascript
浏览器页面区域大小的js获取方法
2013/09/21 Javascript
JS控制一个DIV层在指定时间内消失的方法
2014/02/17 Javascript
jquery动态添加删除一行数据示例
2014/06/12 Javascript
js实现的下拉框二级联动效果
2016/04/30 Javascript
关于Jquery中的bind(),on()绑定事件方式总结
2016/10/26 Javascript
Node.js中文件操作模块File System的详细介绍
2017/01/05 Javascript
vue.js从安装到搭建过程详解
2017/03/17 Javascript
Angular js 实现添加用户、修改密码、敏感字、下拉菜单的综合操作方法
2017/10/24 Javascript
使用Vue的slot插槽分发父组件内容实现高度复用、更加灵活的组件(推荐)
2018/05/01 Javascript
vue3.0 CLI - 2.2 - 组件 home.vue 的初步改造
2018/09/14 Javascript
一个因@click.stop引发的bug的解决
2019/01/08 Javascript
javascript History对象原理解析
2020/02/17 Javascript
[01:23:35]Ti4主赛事胜者组 DK vs EG 1
2014/07/19 DOTA
python中__call__方法示例分析
2014/10/11 Python
python通过zlib实现压缩与解压字符串的方法
2014/11/19 Python
Python matplotlib通过plt.scatter画空心圆标记出特定的点方法
2018/12/13 Python
Python3使用TCP编写一个简易的文件下载器功能
2019/05/08 Python
用Python批量把文件复制到另一个文件夹的实现方法
2019/08/16 Python
Python生成器传参数及返回值原理解析
2020/07/22 Python
利用Opencv实现图片的油画特效实例
2021/02/28 Python
CSS3——齿轮转动关键代码
2013/05/02 HTML / CSS
使用CSS变量实现炫酷惊人的悬浮效果
2019/04/26 HTML / CSS
英国床垫和床架购物网站:Bedman
2019/11/04 全球购物
《风筝》教学反思
2014/04/10 职场文书
《猴子种果树》教学反思
2014/04/26 职场文书
车间安全生产标语
2014/06/06 职场文书
大学迎新标语
2014/06/26 职场文书
2016优秀护士求职自荐信
2016/01/28 职场文书
MYSQL 无法识别中文的永久解决方法
2021/06/03 MySQL
MySQL脏读,幻读和不可重复读
2022/05/11 MySQL