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的js分页代码
Jun 10 Javascript
javascript中的prototype属性使用说明(函数功能扩展)
Aug 16 Javascript
Javascript 类、命名空间、代码组织代码
Jul 31 Javascript
js实现杯子倒水问题自动求解程序
Mar 25 Javascript
JS实现淘宝支付宝网站的控制台菜单效果
Sep 28 Javascript
Javascript实现代码折叠功能
Aug 25 Javascript
AngularJs Understanding the Controller Component
Sep 02 Javascript
vue组件父子间通信之综合练习(聊天室)
Nov 07 Javascript
详解vue-cli之webpack3构建全面提速优化
Dec 25 Javascript
Vue通过WebSocket建立长连接的实现代码
Nov 05 Javascript
vue使用自定义事件的表单输入组件用法详解【日期组件与货币组件】
Jun 01 Javascript
解决Vue 移动端点击出现300毫秒延迟的问题
Jul 21 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
最省空间的计数器
2006/10/09 PHP
php下用cookie统计用户访问网页次数的代码
2010/05/09 PHP
linux iconv方法的使用
2011/10/01 PHP
php启用sphinx全文搜索的实现方法
2014/12/24 PHP
php获取开始与结束日期之间所有日期的方法
2016/11/29 PHP
PHPTree――php快速生成无限级分类
2018/03/30 PHP
浅谈laravel框架与thinkPHP框架的区别
2019/10/23 PHP
Laravel 5+ .env环境配置文件详解
2020/04/06 PHP
JavaScript 事件对象的实现
2009/07/13 Javascript
可以用来调试JavaScript错误的解决方案
2010/08/07 Javascript
jquery实现横向图片轮播特效代码分享
2015/11/19 Javascript
js操作数据库实现注册和登陆的简单实例
2016/05/26 Javascript
快速解决js动态改变dom元素属性后页面及时渲染的问题
2016/07/06 Javascript
jQuery表单插件ajaxForm实例详解
2017/01/17 Javascript
正则表达式基本语法及表单验证操作详解【基于JS】
2017/04/07 Javascript
ES6 javascript中class类的get与set用法实例分析
2017/10/30 Javascript
浅谈vue,angular,react数据双向绑定原理分析
2017/11/28 Javascript
javascript实现拖拽碰撞检测
2020/03/12 Javascript
Vue 请求传公共参数的操作
2020/07/31 Javascript
vue 导航锚点_点击平滑滚动,导航栏对应变化详解
2020/08/10 Javascript
js+css3实现炫酷时钟
2020/08/18 Javascript
Python使用wget实现下载网络文件功能示例
2018/05/31 Python
利用jupyter网页版本进行python函数查询方式
2020/04/14 Python
python批量修改文件名的示例
2020/09/27 Python
python中字典增加和删除使用方法
2020/09/30 Python
pip/anaconda修改镜像源,加快python模块安装速度的操作
2021/03/04 Python
Groupon西班牙官方网站:在线优惠券和交易,节省高达70%
2021/03/13 全球购物
Python面试题:如何用Python来发送邮件
2016/03/15 面试题
最美孝心少年事迹材料
2014/08/15 职场文书
银行业务授权委托书
2014/10/10 职场文书
审计局2014法制宣传日活动总结
2014/11/01 职场文书
2014旅游局党组书记党建工作汇报材料
2014/11/02 职场文书
2016年清明节红领巾广播稿
2015/12/17 职场文书
浅谈Redis在直播场景的实践方案
2021/04/27 Redis
React列表栏及购物车组件使用详解
2021/06/28 Javascript
Python使用永中文档转换服务
2022/05/06 Python