JavaScript变量的作用域全解析


Posted in Javascript onAugust 14, 2015

变量作用域是程序中定义这个变量的区域。
先来看一段示例:

/*  代码1  */

var scope = "global ";
function checkScope() {
 var scope = "local ";
 function childCheck() {
  var scope = "childLocal ";
  document.write(scope);
 }
 function childUndefined() {
  document.write(scope);
  var scope;
 }
 function childOverride() {
  scope = "childOverride ";
  document.write(scope);
 }
 document.write(scope); //输出"local"
 childCheck();   //输出"childLocal"
 childUndefined();  //输出"undefined"
 childOverride();  //输出"childOverride"
 document.write(scope); //输出"childOverride"
}
checkScope();    //输出"local childLocal undefinedchildOverride childOverride"
document.write(scope);  //输出"global "

全局作用域与局部作用域
全局(global)变量的作用域是全局的,在Javascript中处处有定义;而函数内部声明的变量是局部(local)变量,其作用域是局部性的,只在函数体内部有定义。对于下面的输出读者应不会感到意外。
/*  代码2  */

var scope = "global";
function checkScope() {
 var scope = "local";
 document.write(scope);
}
checkScope();   //输出"local"
document.write(scope); //输出"global"

全局变量作用域中使用变量可以不用var语句,但在声明局部变量是一定要使用var语句,否则会视为对全局变量的引用。看下面代码:
/*  代码3  */

var scope = "global";
function checkScope() {
 scope = "local";
 document.write(scope);
}
checkScope();   //输出"local"
document.write(scope); //输出"local"

没有块作用域
Javascript没有块级作用域,函数中声明的变量在整个函数中都是有定义的。对于下面的代码对于生疏的读者可能颇感意外:
/*  代码4  */

var scope = "global";
function checkScope() {
 document.write(scope); //语句4.1
 var scope = "local"; //语句4.2
 document.write(scope);
}
checkScope();   //输出"undefinedlocal"

由于语句4.1(var scope = "local";)声明的变量在整个checkScope函数作用域内都有效,因此在语句4.2(document.write(scope); )执行的时scope引用的是局部变量,而此时局部变量scope尚未定义,所以输出”undefined”。因此一个好的编程习惯是将所有的变量声明集中起来放在函数的开头。

在了解了上述内容之后,读者再看看代码1应该不会感到困惑了。
对象的属性变量
对象的属性变量比较容易理解,看一下下面的代码读者应该不会感到疑惑。
/*  代码5  */

var scope = "global ";
var obj = new Object();
obj.scope = "object ";
obj.checkScope = function () {
 var scope = "loacl ";
 document.write(scope);   //输出"loacl"
 document.write(this.scope);  //输出"object"
 document.write(window.scope); //输出"global"
}
obj.checkScope(); //输出"loacl object global"

所谓作用域,就是说这个变量在代码块中的有效范围。如果不理解 JavaScript 作用域,调试代码的时候可能会比较困难。

在函数中,如果用var来声明一个变量,那么该变量的作用域就只限于该函数内部,函数外的代码无法访问该变量。如果在该函数中再声明一个函数,那么这个内部的函数也可以访问这个变量。

反过来,如果声明变量的时候没有用var,那么此变量的作用域就不局限于这个函数了。JavaScript 引擎会再全局范围中检查该变量是否被定义过。如果该变量没有被定义过,那么它就会被定义为一个全局变量。

函数可以访问相同作用域中的变量:

var foo = 'hello';

var sayHello = function() {
 console.log(foo);
};

sayHello();   // logs 'hello'
console.log(foo); // also logs 'hello'

变量作用域之外的代码不能访问该变量:

var sayHello = function() {
 var foo = 'hello';
 console.log(foo);
};

sayHello();   // logs 'hello'
console.log(foo); // doesn't log anything

不用作用域中名称相同的变量,有不同的值:

var foo = 'world';

var sayHello = function() {
 var foo = 'hello';
 console.log(foo);
};

sayHello();   // logs 'hello'
console.log(foo); // logs 'world'

函数定以后可以看到函数内变量值的改变:

var myFunction = function() {
 var foo = 'hello';

 var myFn = function() {
  console.log(foo);
 };

 foo = 'world';

 return myFn;
};

var f = myFunction();
f(); // logs 'world' -- haha

作用域也会穿越 — 闭包

// 一个自执行的匿名函数
(function() {
 var baz = 1;
 var bim = function() { alert(baz); };
 bar = function() { alert(baz); };
})();

console.log(baz); // 在函数外面不能访问 baz

bar(); // 声明 bar 的时候并没有用 var
  // 所以 bar 是一个全局变量; 但是,
  // bar 和 baz 在相同的作用域内被定义,
  // 所以 bar 可以访问 baz
  // 其实 bar 是个闭包函数

bim(); // bim 的作用域只限于匿名函数内部,
  // 所以这里不能调用

综合

所谓作用域,就是说这个变量在代码块中的有效范围。如果不理解 JavaScript 作用域,调试代码的时候可能会比较困难。

在函数中,如果用var来声明一个变量,那么该变量的作用域就只限于该函数内部,函数外的代码无法访问该变量。如果在该函数中再声明一个函数,那么这个内部的函数也可以访问这个变量。

反过来,如果声明变量的时候没有用var,那么此变量的作用域就不局限于这个函数了。JavaScript 引擎会再全局范围中检查该变量是否被定义过。如果该变量没有被定义过,那么它就会被定义为一个全局变量。

函数可以访问相同作用域中的变量:

var foo = 'hello';

var sayHello = function() {
 console.log(foo);
};

sayHello();   // logs 'hello'
console.log(foo); // also logs 'hello'

变量作用域之外的代码不能访问该变量:

var sayHello = function() {
 var foo = 'hello';
 console.log(foo);
};

sayHello();   // logs 'hello'
console.log(foo); // doesn't log anything

不用作用域中名称相同的变量,有不同的值:

var foo = 'world';

var sayHello = function() {
 var foo = 'hello';
 console.log(foo);
};

sayHello();   // logs 'hello'
console.log(foo); // logs 'world'

函数定以后可以看到函数内变量值的改变:

 
var myFunction = function() {
 var foo = 'hello';

 var myFn = function() {
  console.log(foo);
 };

 foo = 'world';

 return myFn;
};

var f = myFunction();
f(); // logs 'world' -- haha

作用域也会穿越 — 闭包

// 一个自执行的匿名函数
(function() {
 var baz = 1;
 var bim = function() { alert(baz); };
 bar = function() { alert(baz); };
})();

console.log(baz); // 在函数外面不能访问 baz

bar(); // 声明 bar 的时候并没有用 var
  // 所以 bar 是一个全局变量; 但是,
  // bar 和 baz 在相同的作用域内被定义,
  // 所以 bar 可以访问 baz
  // 其实 bar 是个闭包函数

bim(); // bim 的作用域只限于匿名函数内部,
  // 所以这里不能调用
Javascript 相关文章推荐
基于jquery的复制网页内容到WORD的实现代码
Feb 16 Javascript
js函数名与form表单元素同名冲突的问题
Mar 07 Javascript
JS替换字符串中字符即替换全部而不是第一个
Jun 04 Javascript
Jquery中扩展方法extend使用技巧
Aug 24 Javascript
JavaScript字符串对象的concat方法实例(用于连接两个或多个字符串)
Oct 16 Javascript
JS实现的网页背景闪电闪烁效果代码
Oct 17 Javascript
JS+HTML5手机开发之滚动和惯性缓动实现方法分析
Jun 12 Javascript
jQuery 限制输入字符串长度
Jun 20 Javascript
通过fastclick源码分析彻底解决tap“点透”
Dec 24 Javascript
通过cordova将vue项目打包为webapp的方法
Feb 02 Javascript
JavaScript 判断数据类型的4种方法
Sep 11 Javascript
如何使用CocosCreator对象池
Apr 14 Javascript
DEDECMS如何为文章添加HOT NEW标志图片
Aug 14 #Javascript
JavaScript实现给按钮加上双重动作的方法
Aug 14 #Javascript
详解jQuery中的元素的属性和相关操作
Aug 14 #Javascript
js实现人才网站职位选择功能的方法
Aug 14 #Javascript
jQuery入门基础知识学习指南
Aug 14 #Javascript
Jquery全选与反选点击执行一次的解决方案
Aug 14 #Javascript
js实现Select列表各项上移和下移的方法
Aug 14 #Javascript
You might like
php仿ZOL分页类代码
2008/10/02 PHP
php面向对象全攻略 (二) 实例化对象 使用对象成员
2009/09/30 PHP
php生成随机密码的三种方法小结
2010/09/04 PHP
php+ajax实现无刷新分页的方法
2014/11/04 PHP
PHP stream_context_create()函数的使用示例
2015/05/12 PHP
PHP获取音频文件的相关信息
2015/06/22 PHP
北京奥运官方网站幻灯切换效果flash版打包下载
2008/01/30 Javascript
JQuery拖拽元素改变大小尺寸实现代码
2012/12/10 Javascript
键盘上一张下一张兼容IE/google/firefox等浏览器
2014/01/28 Javascript
关于微信上网页图片点击全屏放大效果
2016/12/19 Javascript
uploader秒传图片到服务器完整代码
2017/04/22 Javascript
JavaScript实现滑动门效果
2020/01/18 Javascript
微信小程序订阅消息(java后端实现)开发
2020/06/01 Javascript
vue.js实现点击图标放大离开时缩小的代码
2021/01/27 Vue.js
[04:04]显微镜下的DOTA2第六期——电影级别的华丽团战
2014/06/20 DOTA
python模拟登陆阿里妈妈生成商品推广链接
2014/04/03 Python
Python with的用法
2014/08/22 Python
Python中的生成器和yield详细介绍
2015/01/09 Python
Python最长公共子串算法实例
2015/03/07 Python
Python实现周期性抓取网页内容的方法
2015/11/04 Python
使用pandas对两个dataframe进行join的实例
2018/06/08 Python
python实现n个数中选出m个数的方法
2018/11/13 Python
如何在Django中设置定时任务的方法示例
2019/01/18 Python
详解Python打包分发工具setuptools
2019/08/05 Python
pytorch中如何使用DataLoader对数据集进行批处理的方法
2019/08/06 Python
在Python中画图(基于Jupyter notebook的魔法函数)
2019/10/28 Python
Python将列表中的元素转化为数字并排序的示例
2019/12/25 Python
Python列表如何更新值
2020/05/27 Python
python中什么是面向对象
2020/06/11 Python
Python分类测试代码实例汇总
2020/07/23 Python
存储过程和函数的区别
2013/05/28 面试题
购房协议书
2014/04/11 职场文书
银行竞聘演讲稿范文
2014/04/23 职场文书
文明之星事迹材料
2014/05/09 职场文书
2014大学生学生会工作总结
2014/12/19 职场文书
幼儿园感恩节活动总结
2015/03/24 职场文书