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 相关文章推荐
JavaScript高级程序设计(第3版)学习笔记5 js语句
Oct 11 Javascript
使用jQuery时Form表单元素ID和name命名大忌
Mar 06 Javascript
两行代码轻松搞定JavaScript日期验证
Aug 03 Javascript
node.js实现博客小爬虫的实例代码
Oct 08 Javascript
easyui messager alert 三秒后自动关闭提示的实例
Nov 07 Javascript
详解vue.js组件化开发实践
Dec 14 Javascript
漂亮实用的页面loading(加载)封装代码
Feb 03 Javascript
vue.js评论发布信息可插入QQ表情功能
Aug 08 Javascript
JavaScript门面模式详解
Oct 19 Javascript
详解如何使用koa实现socket.io官网的例子
Nov 04 Javascript
vue基于better-scroll实现左右联动滑动页面
Jun 30 Javascript
JavaScript对象访问器Getter及Setter原理解析
Dec 08 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
一个ftp类(ini.php)
2006/10/09 PHP
php 表单验证实现代码
2009/03/10 PHP
php 检查电子邮件函数(自写)
2014/01/16 PHP
Javascript与PHP验证用户输入URL地址是否正确
2014/10/09 PHP
php删除文本文件中重复行的方法
2015/04/28 PHP
php版微信数据统计接口用法示例
2016/10/12 PHP
不错的一个日期输入 动态
2006/11/06 Javascript
escape、encodeURI、encodeURIComponent等方法的区别比较
2006/12/27 Javascript
javascript+xml技术实现分页浏览
2008/07/27 Javascript
jQuery 可以拖动的div实现代码 脚本之家修正版
2009/06/26 Javascript
JavaScript中各种编码解码函数的区别和注意事项
2010/08/19 Javascript
js面向对象设计用{}好还是function(){}好(构造函数)
2011/10/23 Javascript
jQuery语法总结和注意事项小结
2012/11/11 Javascript
如何在指定的地方插入html内容和文本内容
2013/12/23 Javascript
简单选项卡 js和jquery制作方法分享
2014/02/26 Javascript
js判断手机和pc端选择不同执行事件的方法
2015/01/30 Javascript
Javascript URI 解析介绍
2015/03/15 Javascript
基于Bootstrap重置输入框内容按钮插件
2016/05/12 Javascript
jQuery中的insertBefore(),insertAfter(),after(),before()区别介绍
2016/09/01 Javascript
Bootstrap如何激活导航状态
2017/03/22 Javascript
element ui 对话框el-dialog关闭事件详解
2018/02/26 Javascript
vue实现的下拉框功能示例
2019/01/29 Javascript
vue.js基于v-for实现批量渲染 Json数组对象列表数据示例
2019/08/03 Javascript
Selenium控制浏览器常见操作示例
2018/08/13 Python
python读取图片的方式,以及将图片以三维数组的形式输出方法
2019/07/03 Python
使用tqdm显示Python代码执行进度功能
2019/12/08 Python
python 串口读取+存储+输出处理实例
2019/12/26 Python
Pytest参数化parametrize使用代码实例
2020/02/22 Python
欧洲最大的球衣网上商店:Kitbag
2017/11/11 全球购物
军训自我鉴定
2013/12/14 职场文书
竞选体育委员演讲稿
2014/04/26 职场文书
个人违纪检讨书
2014/09/15 职场文书
2014年党的群众路线整改措施思想汇报
2014/10/12 职场文书
2014年个人工作总结报告
2014/11/27 职场文书
介绍信模板
2015/01/31 职场文书
品牌形象定位,全面分析
2019/07/23 职场文书