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 ajax cache缓存问题
Jul 01 Javascript
体验js中splice()的强大(插入、删除或替换数组的元素)
Jan 16 Javascript
浅析JS刷新框架中的其他页面 && JS刷新窗口方法汇总
Jul 08 Javascript
Js放到HTML文件中的哪个位置有什么区别
Aug 21 Javascript
JS实现模仿微博发布效果实例代码
Dec 16 Javascript
原生javascript模仿win8等待提示圆圈进度条
Apr 24 Javascript
js获取当前日期前七天的方法
Feb 28 Javascript
基于BootStrap Metronic开发框架经验小结【九】实现Web页面内容的打印预览和保存操作
May 12 Javascript
深入理解ECMAScript的几个关键语句
Jun 01 Javascript
对Vue.js之事件的绑定(v-on: 或者 @ )详解
Sep 15 Javascript
D3.js(v3)+react 实现带坐标与比例尺的柱形图 (V3版本)
May 09 Javascript
jquery实现垂直手风琴菜单
Mar 04 jQuery
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中ob(Output Buffer 输出缓冲)函数使用方法
2007/07/21 PHP
php自动加载方式集合
2016/04/04 PHP
浅谈php中变量的数据类型判断函数
2017/03/04 PHP
对象的类型:本地对象(1)
2006/12/29 Javascript
JavaScript delete操作符应用实例
2009/01/13 Javascript
jQuery 标题的自动翻转实现代码
2009/10/14 Javascript
你一定会收藏的Nodejs代码片段
2016/02/04 NodeJs
基于javascript实现精确到毫秒的倒计时限时抢购
2016/04/17 Javascript
浅析Javascript中bind()方法的使用与实现
2016/04/29 Javascript
全国省市二级联动下拉菜单 js版
2016/05/10 Javascript
JavaScript正则表达式实例详解
2016/10/16 Javascript
Bootstrap 手风琴菜单的实现代码
2017/01/20 Javascript
详解vue-property-decorator使用手册
2019/07/29 Javascript
微信小程序下拉框搜索功能的实现方法
2019/07/31 Javascript
详解Vscode中使用Eslint终极配置大全
2019/11/08 Javascript
vant自定义二级菜单操作
2020/11/02 Javascript
Python引用类型和值类型的区别与使用解析
2017/10/17 Python
Django 登陆验证码和中间件的实现
2018/08/17 Python
selenium+python自动化测试之使用webdriver操作浏览器的方法
2019/01/23 Python
Python 抓取微信公众号账号信息的方法
2019/06/14 Python
python连接mongodb集群方法详解
2020/02/13 Python
Python telnet登陆功能实现代码
2020/04/16 Python
python实现杨辉三角的几种方法代码实例
2021/03/02 Python
Html5内唤醒百度、高德APP的实现示例
2019/05/20 HTML / CSS
HTML5 绘制图像(上)之:关于canvas元素引领下一代web页面的问题
2013/04/24 HTML / CSS
香港连卡佛百货官网:Lane Crawford
2019/09/04 全球购物
戴森香港官方网站:Dyson香港
2021/02/11 全球购物
struct和class的区别
2015/11/20 面试题
《庐山的云雾》教学反思
2014/04/22 职场文书
我的中国梦演讲稿500字
2014/08/19 职场文书
缓刑人员思想汇报500字
2014/09/12 职场文书
基层干部群众路线教育实践活动个人对照检查材料
2014/09/23 职场文书
2015年世界无烟日演讲稿
2015/03/18 职场文书
Nginx性能优化之Gzip压缩设置详解(最大程度提高页面打开速度)
2022/02/12 Servers
彻底弄懂Python中的回调函数(callback)
2022/06/25 Python
Win10玩csgo闪退如何解决?Win10玩csgo闪退的解决方法
2022/07/23 数码科技